diff --git a/change-proneness-ranker/pom.xml b/change-proneness-ranker/pom.xml index 686b4146..0bc9b94f 100644 --- a/change-proneness-ranker/pom.xml +++ b/change-proneness-ranker/pom.xml @@ -5,7 +5,7 @@ org.hjug.refactorfirst refactor-first - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT org.hjug.refactorfirst.changepronenessranker diff --git a/circular-reference-detector/pom.xml b/circular-reference-detector/pom.xml index 6d38129b..c72189c1 100644 --- a/circular-reference-detector/pom.xml +++ b/circular-reference-detector/pom.xml @@ -4,7 +4,7 @@ org.hjug.refactorfirst refactor-first - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT org.hjug.refactorfirst.circularreferencedetector @@ -13,6 +13,16 @@ Tool to help detecting circular references by parsing a java project. + + org.projectlombok + lombok + ${lombok.version} + + + org.slf4j + slf4j-api + 1.7.26 + org.jgrapht jgrapht-core @@ -35,6 +45,7 @@ 5.9.0 test + diff --git a/circular-reference-detector/src/main/java/org/hjug/parser/JavaProjectParser.java b/circular-reference-detector/src/main/java/org/hjug/parser/JavaProjectParser.java index 51c1700f..f450d77d 100644 --- a/circular-reference-detector/src/main/java/org/hjug/parser/JavaProjectParser.java +++ b/circular-reference-detector/src/main/java/org/hjug/parser/JavaProjectParser.java @@ -14,10 +14,12 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; +import lombok.extern.slf4j.Slf4j; import org.jgrapht.Graph; import org.jgrapht.graph.DefaultDirectedWeightedGraph; import org.jgrapht.graph.DefaultWeightedEdge; +@Slf4j public class JavaProjectParser { /** @@ -37,6 +39,7 @@ public Graph getClassReferences(String srcDirectory filesStream .filter(path -> path.getFileName().toString().endsWith(".java")) .forEach(path -> { + log.info("Parsing {}", path); List types = getInstanceVarTypes(classNames, path.toFile()); types.addAll(getMethodArgumentTypes(classNames, path.toFile())); if (!types.isEmpty()) { diff --git a/cli/pom.xml b/cli/pom.xml index ec63469e..bc331243 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -4,7 +4,7 @@ org.hjug.refactorfirst refactor-first - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT jar diff --git a/cost-benefit-calculator/pom.xml b/cost-benefit-calculator/pom.xml index be1069e2..e4312013 100644 --- a/cost-benefit-calculator/pom.xml +++ b/cost-benefit-calculator/pom.xml @@ -5,7 +5,7 @@ org.hjug.refactorfirst refactor-first - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT org.hjug.refactorfirst.costbenefitcalculator diff --git a/coverage/pom.xml b/coverage/pom.xml index fde039ee..64ddb094 100644 --- a/coverage/pom.xml +++ b/coverage/pom.xml @@ -7,7 +7,7 @@ org.hjug.refactorfirst refactor-first - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT coverage diff --git a/effort-ranker/pom.xml b/effort-ranker/pom.xml index 1186a68d..838d88bf 100644 --- a/effort-ranker/pom.xml +++ b/effort-ranker/pom.xml @@ -5,7 +5,7 @@ org.hjug.refactorfirst refactor-first - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT org.hjug.refactorfirst.effortranker @@ -20,7 +20,7 @@ org.hjug.refactorfirst.testresources test-resources - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT diff --git a/graph-data-generator/pom.xml b/graph-data-generator/pom.xml index 572432aa..586a3a72 100644 --- a/graph-data-generator/pom.xml +++ b/graph-data-generator/pom.xml @@ -5,7 +5,7 @@ org.hjug.refactorfirst refactor-first - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT org.hjug.refactorfirst.graphdatagenerator @@ -15,7 +15,7 @@ org.hjug.refactorfirst.costbenefitcalculator cost-benefit-calculator - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT diff --git a/pom.xml b/pom.xml index f22dcc58..b0b47b05 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.hjug.refactorfirst refactor-first - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT pom https://github.com/refactorfirst/RefactorFirst diff --git a/refactor-first-maven-plugin/pom.xml b/refactor-first-maven-plugin/pom.xml index 01586e00..860462e7 100644 --- a/refactor-first-maven-plugin/pom.xml +++ b/refactor-first-maven-plugin/pom.xml @@ -5,7 +5,7 @@ org.hjug.refactorfirst refactor-first - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT org.hjug.refactorfirst.plugin diff --git a/refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstMavenReport.java b/refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstMavenReport.java index 69cfb03e..e5ee6a82 100644 --- a/refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstMavenReport.java +++ b/refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstMavenReport.java @@ -68,10 +68,6 @@ public String getDescription(Locale locale) { + " have the highest priority values."; } - public final String[] cycleTableHeadings = { - "Cycle Name", "Priority", "Change Proneness Rank", "Class Count", "Relationship Count", "Minimum Cuts" - }; - public final String[] classCycleTableHeadings = {"Classes", "Relationships"}; private Graph classGraph; @@ -164,6 +160,28 @@ public void executeReport(Locale locale) throws MavenReportException { mainSink.unknown(script, new Object[] {HtmlMarkup.TAG_TYPE_START}, cboJavascript); mainSink.unknown(script, new Object[] {HtmlMarkup.TAG_TYPE_END}, null); + + SinkEventAttributeSet d3js = new SinkEventAttributeSet(); + d3js.addAttribute(SinkEventAttributes.TYPE, "text/javascript"); + d3js.addAttribute(SinkEventAttributes.SRC, "https://d3js.org/d3.v5.min.js"); + + mainSink.unknown(script, new Object[] {HtmlMarkup.TAG_TYPE_START}, d3js); + mainSink.unknown(script, new Object[] {HtmlMarkup.TAG_TYPE_END}, null); + + SinkEventAttributeSet graphViz = new SinkEventAttributeSet(); + graphViz.addAttribute(SinkEventAttributes.TYPE, "text/javascript"); + graphViz.addAttribute(SinkEventAttributes.SRC, "https://unpkg.com/d3-graphviz@3.0.5/build/d3-graphviz.min.js"); + + mainSink.unknown(script, new Object[] {HtmlMarkup.TAG_TYPE_START}, graphViz); + mainSink.unknown(script, new Object[] {HtmlMarkup.TAG_TYPE_END}, null); + + SinkEventAttributeSet wasm = new SinkEventAttributeSet(); + wasm.addAttribute(SinkEventAttributes.TYPE, "text/javascript"); + wasm.addAttribute(SinkEventAttributes.SRC, "https://unpkg.com/@hpcc-js/wasm@0.3.11/dist/index.min.js"); + + mainSink.unknown(script, new Object[] {HtmlMarkup.TAG_TYPE_START}, wasm); + mainSink.unknown(script, new Object[] {HtmlMarkup.TAG_TYPE_END}, null); + mainSink.head_(); mainSink.body(); @@ -472,12 +490,26 @@ private void renderCycles( mainSink.section2_(); mainSink.division_(); + mainSink.paragraph(alignCenter); + mainSink.text("Note: often only one minimum cut relationship needs to be removed"); + mainSink.paragraph_(); + mainSink.table(); mainSink.tableRows(new int[] {Sink.JUSTIFY_LEFT}, true); // Content // header row + String[] cycleTableHeadings; + if (showDetails) { + cycleTableHeadings = new String[] { + "Cycle Name", "Priority", "Change Proneness Rank", "Class Count", "Relationship Count", "Minimum Cuts" + }; + } else { + cycleTableHeadings = + new String[] {"Cycle Name", "Priority", "Class Count", "Relationship Count", "Minimum Cuts"}; + } + mainSink.tableRow(); for (String heading : cycleTableHeadings) { drawTableHeaderCell(heading, mainSink); @@ -492,15 +524,27 @@ private void renderCycles( edgesToCut.append(minCutEdge + ":" + (int) classGraph.getEdgeWeight(minCutEdge)); } - // "Cycle Name", "Priority", "Change Proneness Rank", "Class Count", "Relationship Count", "Min Cuts" - String[] rankedCycleData = { - rankedCycle.getCycleName(), - rankedCycle.getPriority().toString(), - rankedCycle.getChangePronenessRank().toString(), - String.valueOf(rankedCycle.getCycleNodes().size()), - String.valueOf(rankedCycle.getEdgeSet().size()), - edgesToCut.toString() - }; + String[] rankedCycleData; + if (showDetails) { + // "Cycle Name", "Priority", "Change Proneness Rank", "Class Count", "Relationship Count", "Min Cuts" + rankedCycleData = new String[] { + rankedCycle.getCycleName(), + rankedCycle.getPriority().toString(), + rankedCycle.getChangePronenessRank().toString(), + String.valueOf(rankedCycle.getCycleNodes().size()), + String.valueOf(rankedCycle.getEdgeSet().size()), + edgesToCut.toString() + }; + } else { + // "Cycle Name", "Priority", "Class Count", "Relationship Count", "Min Cuts" + rankedCycleData = new String[] { + rankedCycle.getCycleName(), + rankedCycle.getPriority().toString(), + String.valueOf(rankedCycle.getCycleNodes().size()), + String.valueOf(rankedCycle.getEdgeSet().size()), + edgesToCut.toString() + }; + } for (String rowData : rankedCycleData) { drawCycleTableCell(rowData, mainSink); @@ -513,12 +557,11 @@ private void renderCycles( mainSink.table_(); for (RankedCycle rankedCycle : rankedCycles) { - renderCycleTable(outputDirectory, mainSink, rankedCycle, formatter); + renderCycle(outputDirectory, mainSink, rankedCycle, formatter); } } - private void renderCycleTable( - String outputDirectory, Sink mainSink, RankedCycle cycle, DateTimeFormatter formatter) { + private void renderCycle(String outputDirectory, Sink mainSink, RankedCycle cycle, DateTimeFormatter formatter) { mainSink.lineBreak(); mainSink.lineBreak(); @@ -537,7 +580,7 @@ private void renderCycleTable( mainSink.section2_(); mainSink.division_(); - renderCycleImage(cycle.getCycleName(), mainSink, outputDirectory); + renderCycleImage(classGraph, cycle, mainSink); mainSink.division(alignCenter); mainSink.bold(); @@ -580,25 +623,6 @@ private void renderCycleTable( mainSink.table_(); } - public void renderCycleImage(String cycleName, Sink mainSink, String outputDirectory) { - SinkEventAttributeSet alignCenter = new SinkEventAttributeSet(); - alignCenter.addAttribute(SinkEventAttributes.ALIGN, "center"); - mainSink.division(alignCenter); - - SinkEventAttributeSet imageAttributes = new SinkEventAttributeSet(); - imageAttributes.addAttribute(SinkEventAttributes.TYPE, "img"); - imageAttributes.addAttribute(SinkEventAttributes.SRC, "./refactorFirst/cycles/graph" + cycleName + ".png"); - imageAttributes.addAttribute(SinkEventAttributes.WIDTH, 1000); - imageAttributes.addAttribute(SinkEventAttributes.HEIGHT, 1000); - imageAttributes.addAttribute(SinkEventAttributes.ALT, "Cycle " + cycleName); - - mainSink.unknown("img", new Object[] {HtmlMarkup.TAG_TYPE_SIMPLE}, imageAttributes); - - mainSink.division_(); - mainSink.lineBreak(); - mainSink.lineBreak(); - } - private void renderLegend(Sink mainSink, String legendHeading, String xAxis) { SinkEventAttributeSet width = new SinkEventAttributeSet(); width.addAttribute(SinkEventAttributes.STYLE, "width:350px"); @@ -809,4 +833,90 @@ void writeGCBOGchartJs(List rankedDisharmonies, int maxPriorit log.error("Error writing CBO chart script file", e); } } + + void renderCycleImage(Graph classGraph, RankedCycle cycle, Sink mainSink) { + + SinkEventAttributeSet graphDivAttrs = new SinkEventAttributeSet(); + graphDivAttrs.addAttribute(SinkEventAttributes.ALIGN, "center"); + graphDivAttrs.addAttribute(SinkEventAttributes.ID, cycle.getCycleName()); + graphDivAttrs.addAttribute(SinkEventAttributes.STYLE, "border: thin solid black"); + + mainSink.division(graphDivAttrs); + mainSink.division_(); + + String dot = buildDot(classGraph, cycle); + + StringBuilder d3chart = new StringBuilder(); + d3chart.append("d3.select(\"#" + cycle.getCycleName() + "\")\n"); + d3chart.append(".graphviz()\n"); + d3chart.append(".width(screen.width - 300)\n"); + d3chart.append(".height(screen.height)\n"); + d3chart.append(".fit(true)\n"); + d3chart.append(".renderDot(" + dot + ");\n"); + + SinkEventAttributeSet dotChartScript = new SinkEventAttributeSet(); + dotChartScript.addAttribute(SinkEventAttributes.TYPE, "text/javascript"); + + String script = "script"; + mainSink.unknown(script, new Object[] {HtmlMarkup.TAG_TYPE_START}, dotChartScript); + + mainSink.rawText(d3chart.toString()); + mainSink.unknown(script, new Object[] {HtmlMarkup.TAG_TYPE_END}, null); + + SinkEventAttributeSet alignCenter = new SinkEventAttributeSet(); + alignCenter.addAttribute(SinkEventAttributes.ALIGN, "center"); + + mainSink.paragraph(alignCenter); + mainSink.text("Red arrows represent relationship(s) to remove to decompose cycle"); + mainSink.paragraph_(); + + mainSink.lineBreak(); + mainSink.lineBreak(); + } + + String buildDot(Graph classGraph, RankedCycle cycle) { + StringBuilder dot = new StringBuilder(); + + dot.append("'strict digraph G {\\n' +\n"); + + // render vertices + // e.g DownloadManager; + for (String vertex : cycle.getVertexSet()) { + dot.append("'"); + dot.append(vertex); + dot.append(";\\n' +\n"); + } + + for (DefaultWeightedEdge edge : cycle.getEdgeSet()) { + // 'DownloadManager -> Download [ label="1" color="red" ];' + + // render edge + String[] vertexes = + edge.toString().replace("(", "").replace(")", "").split(":"); + + String start = vertexes[0].trim(); + String end = vertexes[1].trim(); + + dot.append("'"); + dot.append(start); + dot.append(" -> "); + dot.append(end); + + // render edge attributes + dot.append(" [ "); + dot.append("label = \""); + dot.append((int) classGraph.getEdgeWeight(edge)); + dot.append("\""); + + if (cycle.getMinCutEdges().contains(edge)) { + dot.append(" color = \"red\""); + } + + dot.append(" ];\\n' +\n"); + } + + dot.append("'}'"); + + return dot.toString(); + } } diff --git a/report/pom.xml b/report/pom.xml index 3fab3259..7bad901e 100644 --- a/report/pom.xml +++ b/report/pom.xml @@ -4,7 +4,7 @@ org.hjug.refactorfirst refactor-first - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT org.hjug.refactorfirst.report diff --git a/report/src/main/java/org/hjug/refactorfirst/report/HtmlReport.java b/report/src/main/java/org/hjug/refactorfirst/report/HtmlReport.java index 45bb08db..88ceaf01 100644 --- a/report/src/main/java/org/hjug/refactorfirst/report/HtmlReport.java +++ b/report/src/main/java/org/hjug/refactorfirst/report/HtmlReport.java @@ -178,12 +178,22 @@ public void renderCycleImage( Graph classGraph, RankedCycle cycle, StringBuilder stringBuilder) { String dot = buildDot(classGraph, cycle); - stringBuilder.append("
\n"); + stringBuilder.append("
\n"); stringBuilder.append("\n"); + + stringBuilder.append("
"); + stringBuilder.append("

Red arrows represent relationship(s) to remove to decompose cycle

"); + stringBuilder.append("
"); + stringBuilder.append("
"); + stringBuilder.append("
"); } String buildDot(Graph classGraph, RankedCycle cycle) { diff --git a/report/src/main/java/org/hjug/refactorfirst/report/SimpleHtmlReport.java b/report/src/main/java/org/hjug/refactorfirst/report/SimpleHtmlReport.java index 5f1e5d75..73db6d1e 100644 --- a/report/src/main/java/org/hjug/refactorfirst/report/SimpleHtmlReport.java +++ b/report/src/main/java/org/hjug/refactorfirst/report/SimpleHtmlReport.java @@ -232,6 +232,8 @@ private void renderCycles( stringBuilder.append( "

Class Cycles by the numbers: (Refactor starting with Priority 1)

\n"); + stringBuilder.append( + "

Note: often only one minimum cut relationship needs to be removed

"); stringBuilder.append("\n"); String[] cycleTableHeadings; diff --git a/test-resources/pom.xml b/test-resources/pom.xml index 9c9891c7..b6863395 100644 --- a/test-resources/pom.xml +++ b/test-resources/pom.xml @@ -5,7 +5,7 @@ org.hjug.refactorfirst refactor-first - 0.5.1-SNAPSHOT + 0.6.0-SNAPSHOT org.hjug.refactorfirst.testresources