1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.report.projectinfo;
20
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.TreeMap;
33
34 import org.apache.maven.artifact.Artifact;
35 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
36 import org.apache.maven.doxia.sink.Sink;
37 import org.apache.maven.doxia.sink.SinkEventAttributes;
38 import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
39 import org.apache.maven.model.Dependency;
40 import org.apache.maven.plugins.annotations.Component;
41 import org.apache.maven.plugins.annotations.Mojo;
42 import org.apache.maven.project.DefaultProjectBuildingRequest;
43 import org.apache.maven.project.MavenProject;
44 import org.apache.maven.project.ProjectBuildingRequest;
45 import org.apache.maven.report.projectinfo.dependencies.DependencyVersionMap;
46 import org.apache.maven.report.projectinfo.dependencies.SinkSerializingDependencyNodeVisitor;
47 import org.apache.maven.reporting.MavenReportException;
48 import org.apache.maven.shared.artifact.filter.StrictPatternIncludesArtifactFilter;
49 import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilder;
50 import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilderException;
51 import org.apache.maven.shared.dependency.graph.DependencyNode;
52 import org.apache.maven.shared.dependency.graph.filter.AncestorOrSelfDependencyNodeFilter;
53 import org.apache.maven.shared.dependency.graph.filter.AndDependencyNodeFilter;
54 import org.apache.maven.shared.dependency.graph.filter.ArtifactDependencyNodeFilter;
55 import org.apache.maven.shared.dependency.graph.filter.DependencyNodeFilter;
56 import org.apache.maven.shared.dependency.graph.traversal.BuildingDependencyNodeVisitor;
57 import org.apache.maven.shared.dependency.graph.traversal.CollectingDependencyNodeVisitor;
58 import org.apache.maven.shared.dependency.graph.traversal.DependencyNodeVisitor;
59 import org.apache.maven.shared.dependency.graph.traversal.FilteringDependencyNodeVisitor;
60
61
62
63
64
65
66
67
68
69 @Mojo(name = "dependency-convergence", aggregator = true)
70 public class DependencyConvergenceReport extends AbstractProjectInfoReport {
71
72
73
74 private static final String IMG_SUCCESS_URL = "images/icon_success_sml.gif";
75
76
77
78
79 private static final String IMG_ERROR_URL = "images/icon_error_sml.gif";
80
81 private static final int FULL_CONVERGENCE = 100;
82
83
84
85
86
87
88
89
90 @Component
91 private DependencyCollectorBuilder dependencyCollectorBuilder;
92
93 private ArtifactFilter filter = null;
94
95 private Map<MavenProject, DependencyNode> projectMap = new HashMap<>();
96
97
98
99
100
101
102
103
104 public String getOutputName() {
105 return "dependency-convergence";
106 }
107
108 @Override
109 protected String getI18Nsection() {
110 return "dependency-convergence";
111 }
112
113
114
115
116
117 @Override
118 protected void executeReport(Locale locale) throws MavenReportException {
119 Sink sink = getSink();
120
121 sink.head();
122 sink.title();
123
124 if (isReactorBuild()) {
125 sink.text(getI18nString(locale, "reactor.title"));
126 } else {
127 sink.text(getI18nString(locale, "title"));
128 }
129
130 sink.title_();
131 sink.head_();
132
133 sink.body();
134
135 sink.section1();
136
137 sink.sectionTitle1();
138
139 if (isReactorBuild()) {
140 sink.text(getI18nString(locale, "reactor.title"));
141 } else {
142 sink.text(getI18nString(locale, "title"));
143 }
144
145 sink.sectionTitle1_();
146
147 DependencyAnalyzeResult dependencyResult = analyzeDependencyTree();
148 int convergence = calculateConvergence(dependencyResult);
149
150 if (convergence < FULL_CONVERGENCE) {
151
152 generateLegend(locale, sink);
153 sink.lineBreak();
154 }
155
156
157 generateStats(locale, sink, dependencyResult);
158
159 sink.section1_();
160
161 if (convergence < FULL_CONVERGENCE) {
162
163 generateConvergence(locale, sink, dependencyResult);
164 }
165
166 sink.body_();
167 sink.flush();
168 sink.close();
169 }
170
171
172
173
174
175
176
177
178
179
180
181 private List<ReverseDependencyLink> getSnapshotDependencies(
182 Map<String, List<ReverseDependencyLink>> dependencyMap) {
183 List<ReverseDependencyLink> snapshots = new ArrayList<>();
184 for (Map.Entry<String, List<ReverseDependencyLink>> entry : dependencyMap.entrySet()) {
185 List<ReverseDependencyLink> depList = entry.getValue();
186 Map<String, List<ReverseDependencyLink>> artifactMap = getSortedUniqueArtifactMap(depList);
187 for (Map.Entry<String, List<ReverseDependencyLink>> artEntry : artifactMap.entrySet()) {
188 String version = artEntry.getKey();
189 boolean isReactorProject = false;
190
191 Iterator<ReverseDependencyLink> iterator = artEntry.getValue().iterator();
192
193
194
195 ReverseDependencyLink rdl = null;
196 if (iterator.hasNext()) {
197 rdl = iterator.next();
198 if (isReactorProject(rdl.getDependency())) {
199 isReactorProject = true;
200 }
201 }
202
203 if (version.endsWith("-SNAPSHOT") && !isReactorProject && rdl != null) {
204 snapshots.add(rdl);
205 }
206 }
207 }
208
209 return snapshots;
210 }
211
212
213
214
215
216
217
218
219 private void generateConvergence(Locale locale, Sink sink, DependencyAnalyzeResult result) {
220 sink.section2();
221
222 sink.sectionTitle2();
223
224 if (isReactorBuild()) {
225 sink.text(getI18nString(locale, "convergence.caption"));
226 } else {
227 sink.text(getI18nString(locale, "convergence.single.caption"));
228 }
229
230 sink.sectionTitle2_();
231
232
233 for (Map.Entry<String, List<ReverseDependencyLink>> entry :
234 result.getConflicting().entrySet()) {
235 String key = entry.getKey();
236 List<ReverseDependencyLink> depList = entry.getValue();
237
238 sink.section3();
239 sink.sectionTitle3();
240 sink.text(key);
241 sink.sectionTitle3_();
242
243 generateDependencyDetails(locale, sink, depList);
244
245 sink.section3_();
246 }
247
248
249 for (ReverseDependencyLink dependencyLink : result.getSnapshots()) {
250 sink.section3();
251 sink.sectionTitle3();
252
253 Dependency dep = dependencyLink.getDependency();
254
255 sink.text(dep.getGroupId() + ":" + dep.getArtifactId());
256 sink.sectionTitle3_();
257
258 List<ReverseDependencyLink> depList = new ArrayList<>();
259 depList.add(dependencyLink);
260 generateDependencyDetails(locale, sink, depList);
261
262 sink.section3_();
263 }
264
265 sink.section2_();
266 }
267
268
269
270
271
272
273
274 private void generateDependencyDetails(Locale locale, Sink sink, List<ReverseDependencyLink> depList) {
275 sink.table();
276 sink.tableRows();
277
278 Map<String, List<ReverseDependencyLink>> artifactMap = getSortedUniqueArtifactMap(depList);
279
280 sink.tableRow();
281
282 sink.tableCell();
283
284 iconError(locale, sink);
285
286 sink.tableCell_();
287
288 sink.tableCell();
289
290 sink.table();
291 sink.tableRows();
292
293 for (String version : artifactMap.keySet()) {
294 sink.tableRow();
295 sink.tableCell(new SinkEventAttributeSet(SinkEventAttributes.WIDTH, "25%"));
296 sink.text(version);
297 sink.tableCell_();
298
299 sink.tableCell();
300 generateVersionDetails(sink, artifactMap, version);
301 sink.tableCell_();
302
303 sink.tableRow_();
304 }
305 sink.tableRows_();
306 sink.table_();
307
308 sink.tableCell_();
309
310 sink.tableRow_();
311
312 sink.tableRows_();
313 sink.table_();
314 }
315
316
317
318
319
320
321
322
323 private void generateVersionDetails(
324 Sink sink, Map<String, List<ReverseDependencyLink>> artifactMap, String version) {
325 sink.numberedList(0);
326 List<ReverseDependencyLink> depList = artifactMap.get(version);
327
328 List<DependencyNode> projectNodes = getProjectNodes(depList);
329
330 if (projectNodes.isEmpty()) {
331 getLog().warn("Can't find project nodes for dependency list: "
332 + depList.get(0).getDependency());
333 return;
334 }
335 Collections.sort(projectNodes, new DependencyNodeComparator());
336
337 for (DependencyNode projectNode : projectNodes) {
338 if (isReactorBuild()) {
339 sink.numberedListItem();
340 }
341
342 showVersionDetails(projectNode, depList, sink);
343
344 if (isReactorBuild()) {
345 sink.numberedListItem_();
346 }
347
348 sink.lineBreak();
349 }
350
351 sink.numberedList_();
352 }
353
354 private List<DependencyNode> getProjectNodes(List<ReverseDependencyLink> depList) {
355 List<DependencyNode> projectNodes = new ArrayList<>();
356
357 for (ReverseDependencyLink depLink : depList) {
358 MavenProject project = depLink.getProject();
359 DependencyNode projectNode = this.projectMap.get(project);
360
361 if (projectNode != null && !projectNodes.contains(projectNode)) {
362 projectNodes.add(projectNode);
363 }
364 }
365 return projectNodes;
366 }
367
368 private void showVersionDetails(DependencyNode projectNode, List<ReverseDependencyLink> depList, Sink sink) {
369 if (depList == null || depList.isEmpty()) {
370 return;
371 }
372
373 Dependency dependency = depList.get(0).getDependency();
374 String key = dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getType() + ":"
375 + dependency.getVersion();
376
377 serializeDependencyTree(projectNode, key, sink);
378 }
379
380
381
382
383
384
385
386 private void serializeDependencyTree(DependencyNode rootNode, String key, Sink sink) {
387 DependencyNodeVisitor visitor = getSerializingDependencyNodeVisitor(sink);
388
389 visitor = new BuildingDependencyNodeVisitor(visitor);
390
391 DependencyNodeFilter nodeFilter = createDependencyNodeFilter(key);
392
393 if (nodeFilter != null) {
394 CollectingDependencyNodeVisitor collectingVisitor = new CollectingDependencyNodeVisitor();
395 DependencyNodeVisitor firstPassVisitor = new FilteringDependencyNodeVisitor(collectingVisitor, nodeFilter);
396 rootNode.accept(firstPassVisitor);
397
398 DependencyNodeFilter secondPassFilter =
399 new AncestorOrSelfDependencyNodeFilter(collectingVisitor.getNodes());
400 visitor = new FilteringDependencyNodeVisitor(visitor, secondPassFilter);
401 }
402
403 rootNode.accept(visitor);
404 }
405
406
407
408
409
410
411 private DependencyNodeFilter createDependencyNodeFilter(String includes) {
412 List<DependencyNodeFilter> filters = new ArrayList<>();
413
414
415 if (includes != null) {
416 List<String> patterns = Arrays.asList(includes.split(","));
417
418 getLog().debug("+ Filtering dependency tree by artifact include patterns: " + patterns);
419
420 ArtifactFilter artifactFilter = new StrictPatternIncludesArtifactFilter(patterns);
421 filters.add(new ArtifactDependencyNodeFilter(artifactFilter));
422 }
423
424 return filters.isEmpty() ? null : new AndDependencyNodeFilter(filters);
425 }
426
427
428
429
430
431 public DependencyNodeVisitor getSerializingDependencyNodeVisitor(Sink sink) {
432 return new SinkSerializingDependencyNodeVisitor(sink);
433 }
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453 private Map<String, List<ReverseDependencyLink>> getSortedUniqueArtifactMap(List<ReverseDependencyLink> depList) {
454 Map<String, List<ReverseDependencyLink>> uniqueArtifactMap = new TreeMap<>();
455
456 for (ReverseDependencyLink rdl : depList) {
457 String key = rdl.getDependency().getVersion();
458 List<ReverseDependencyLink> projectList = uniqueArtifactMap.get(key);
459 if (projectList == null) {
460 projectList = new ArrayList<>();
461 }
462 projectList.add(rdl);
463 uniqueArtifactMap.put(key, projectList);
464 }
465
466 return uniqueArtifactMap;
467 }
468
469
470
471
472
473
474
475 private void generateLegend(Locale locale, Sink sink) {
476 sink.table();
477 sink.tableRows();
478 sink.tableCaption();
479 sink.bold();
480 sink.text(getI18nString(locale, "legend"));
481 sink.bold_();
482 sink.tableCaption_();
483
484 sink.tableRow();
485
486 sink.tableCell();
487 iconError(locale, sink);
488 sink.tableCell_();
489 sink.tableCell();
490 sink.text(getI18nString(locale, "legend.different"));
491 sink.tableCell_();
492
493 sink.tableRow_();
494
495 sink.tableRows_();
496 sink.table_();
497 }
498
499
500
501
502
503
504
505
506 private void generateStats(Locale locale, Sink sink, DependencyAnalyzeResult result) {
507 int depCount = result.getDependencyCount();
508
509 int artifactCount = result.getArtifactCount();
510 int snapshotCount = result.getSnapshotCount();
511 int conflictingCount = result.getConflictingCount();
512
513 int convergence = calculateConvergence(result);
514
515
516 sink.table();
517 sink.tableRows();
518 sink.tableCaption();
519 sink.bold();
520 sink.text(getI18nString(locale, "stats.caption"));
521 sink.bold_();
522 sink.tableCaption_();
523
524 if (isReactorBuild()) {
525 sink.tableRow();
526 sink.tableHeaderCell();
527 sink.text(getI18nString(locale, "stats.modules"));
528 sink.tableHeaderCell_();
529 sink.tableCell();
530 sink.text(String.valueOf(reactorProjects.size()));
531 sink.tableCell_();
532 sink.tableRow_();
533 }
534
535 sink.tableRow();
536 sink.tableHeaderCell();
537 sink.text(getI18nString(locale, "stats.dependencies"));
538 sink.tableHeaderCell_();
539 sink.tableCell();
540 sink.text(String.valueOf(depCount));
541 sink.tableCell_();
542 sink.tableRow_();
543
544 sink.tableRow();
545 sink.tableHeaderCell();
546 sink.text(getI18nString(locale, "stats.artifacts"));
547 sink.tableHeaderCell_();
548 sink.tableCell();
549 sink.text(String.valueOf(artifactCount));
550 sink.tableCell_();
551 sink.tableRow_();
552
553 sink.tableRow();
554 sink.tableHeaderCell();
555 sink.text(getI18nString(locale, "stats.conflicting"));
556 sink.tableHeaderCell_();
557 sink.tableCell();
558 sink.text(String.valueOf(conflictingCount));
559 sink.tableCell_();
560 sink.tableRow_();
561
562 sink.tableRow();
563 sink.tableHeaderCell();
564 sink.text(getI18nString(locale, "stats.snapshots"));
565 sink.tableHeaderCell_();
566 sink.tableCell();
567 sink.text(String.valueOf(snapshotCount));
568 sink.tableCell_();
569 sink.tableRow_();
570
571 sink.tableRow();
572 sink.tableHeaderCell();
573 sink.text(getI18nString(locale, "stats.convergence"));
574 sink.tableHeaderCell_();
575 sink.tableCell();
576 if (convergence < FULL_CONVERGENCE) {
577 iconError(locale, sink);
578 } else {
579 iconSuccess(locale, sink);
580 }
581 sink.nonBreakingSpace();
582 sink.bold();
583 sink.text(String.valueOf(convergence) + " %");
584 sink.bold_();
585 sink.tableCell_();
586 sink.tableRow_();
587
588 sink.tableRow();
589 sink.tableHeaderCell();
590 sink.text(getI18nString(locale, "stats.readyrelease"));
591 sink.tableHeaderCell_();
592 sink.tableCell();
593 if (convergence >= FULL_CONVERGENCE && snapshotCount <= 0) {
594 iconSuccess(locale, sink);
595 sink.nonBreakingSpace();
596 sink.bold();
597 sink.text(getI18nString(locale, "stats.readyrelease.success"));
598 sink.bold_();
599 } else {
600 iconError(locale, sink);
601 sink.nonBreakingSpace();
602 sink.bold();
603 sink.text(getI18nString(locale, "stats.readyrelease.error"));
604 sink.bold_();
605 if (convergence < FULL_CONVERGENCE) {
606 sink.lineBreak();
607 sink.text(getI18nString(locale, "stats.readyrelease.error.convergence"));
608 }
609 if (snapshotCount > 0) {
610 sink.lineBreak();
611 sink.text(getI18nString(locale, "stats.readyrelease.error.snapshots"));
612 }
613 }
614 sink.tableCell_();
615 sink.tableRow_();
616
617 sink.tableRows_();
618 sink.table_();
619 }
620
621
622
623
624
625
626
627 private boolean isReactorProject(Dependency dependency) {
628 for (MavenProject mavenProject : reactorProjects) {
629 if (mavenProject.getGroupId().equals(dependency.getGroupId())
630 && mavenProject.getArtifactId().equals(dependency.getArtifactId())) {
631 if (getLog().isDebugEnabled()) {
632 getLog().debug(dependency + " is a reactor project");
633 }
634 return true;
635 }
636 }
637 return false;
638 }
639
640 private boolean isReactorBuild() {
641 return this.reactorProjects.size() > 1;
642 }
643
644 private void iconSuccess(Locale locale, Sink sink) {
645 SinkEventAttributes attributes =
646 new SinkEventAttributeSet(SinkEventAttributes.ALT, getI18nString(locale, "icon.success"));
647 sink.figureGraphics(IMG_SUCCESS_URL, attributes);
648 }
649
650 private void iconError(Locale locale, Sink sink) {
651 SinkEventAttributes attributes =
652 new SinkEventAttributeSet(SinkEventAttributes.ALT, getI18nString(locale, "icon.error"));
653 sink.figureGraphics(IMG_ERROR_URL, attributes);
654 }
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677 private DependencyAnalyzeResult analyzeDependencyTree() throws MavenReportException {
678 Map<String, List<ReverseDependencyLink>> conflictingDependencyMap = new TreeMap<>();
679 Map<String, List<ReverseDependencyLink>> allDependencies = new TreeMap<>();
680
681 ProjectBuildingRequest buildingRequest =
682 new DefaultProjectBuildingRequest(getSession().getProjectBuildingRequest());
683
684 for (MavenProject reactorProject : reactorProjects) {
685 buildingRequest.setProject(reactorProject);
686
687 DependencyNode node = getNode(buildingRequest);
688
689 this.projectMap.put(reactorProject, node);
690
691 getConflictingDependencyMap(conflictingDependencyMap, reactorProject, node);
692
693 getAllDependencyMap(allDependencies, reactorProject, node);
694 }
695
696 return populateDependencyAnalyzeResult(conflictingDependencyMap, allDependencies);
697 }
698
699
700
701
702
703
704
705
706
707 private DependencyAnalyzeResult populateDependencyAnalyzeResult(
708 Map<String, List<ReverseDependencyLink>> conflictingDependencyMap,
709 Map<String, List<ReverseDependencyLink>> allDependencies) {
710 DependencyAnalyzeResult dependencyResult = new DependencyAnalyzeResult();
711
712 dependencyResult.setAll(allDependencies);
713 dependencyResult.setConflicting(conflictingDependencyMap);
714
715 List<ReverseDependencyLink> snapshots = getSnapshotDependencies(allDependencies);
716 dependencyResult.setSnapshots(snapshots);
717 return dependencyResult;
718 }
719
720
721
722
723
724
725
726
727 private void getConflictingDependencyMap(
728 Map<String, List<ReverseDependencyLink>> conflictingDependencyMap,
729 MavenProject reactorProject,
730 DependencyNode node) {
731 DependencyVersionMap visitor = new DependencyVersionMap();
732 visitor.setUniqueVersions(true);
733
734 node.accept(visitor);
735
736 for (List<DependencyNode> nodes : visitor.getConflictedVersionNumbers()) {
737 DependencyNode dependencyNode = nodes.get(0);
738
739 String key = dependencyNode.getArtifact().getGroupId() + ":"
740 + dependencyNode.getArtifact().getArtifactId();
741
742 List<ReverseDependencyLink> dependencyList = conflictingDependencyMap.get(key);
743 if (dependencyList == null) {
744 dependencyList = new ArrayList<>();
745 }
746
747 dependencyList.add(new ReverseDependencyLink(toDependency(dependencyNode.getArtifact()), reactorProject));
748
749 for (DependencyNode workNode : nodes.subList(1, nodes.size())) {
750 dependencyList.add(new ReverseDependencyLink(toDependency(workNode.getArtifact()), reactorProject));
751 }
752
753 conflictingDependencyMap.put(key, dependencyList);
754 }
755 }
756
757
758
759
760
761
762
763
764 private void getAllDependencyMap(
765 Map<String, List<ReverseDependencyLink>> allDependencies,
766 MavenProject reactorProject,
767 DependencyNode node) {
768 Set<Artifact> artifacts = getAllDescendants(node);
769
770 for (Artifact art : artifacts) {
771 String key = art.getGroupId() + ":" + art.getArtifactId();
772
773 List<ReverseDependencyLink> reverseDepependencies = allDependencies.get(key);
774 if (reverseDepependencies == null) {
775 reverseDepependencies = new ArrayList<>();
776 }
777
778 if (!containsDependency(reverseDepependencies, art)) {
779 reverseDepependencies.add(new ReverseDependencyLink(toDependency(art), reactorProject));
780 }
781
782 allDependencies.put(key, reverseDepependencies);
783 }
784 }
785
786
787
788
789
790
791
792 private Dependency toDependency(Artifact artifact) {
793 Dependency dependency = new Dependency();
794 dependency.setGroupId(artifact.getGroupId());
795 dependency.setArtifactId(artifact.getArtifactId());
796 dependency.setVersion(artifact.getVersion());
797 dependency.setClassifier(artifact.getClassifier());
798 dependency.setScope(artifact.getScope());
799
800 return dependency;
801 }
802
803
804
805
806
807
808
809
810 private boolean containsDependency(List<ReverseDependencyLink> reverseDependencies, Artifact art) {
811
812 for (ReverseDependencyLink revDependency : reverseDependencies) {
813 Dependency dep = revDependency.getDependency();
814 if (dep.getGroupId().equals(art.getGroupId())
815 && dep.getArtifactId().equals(art.getArtifactId())
816 && dep.getVersion().equals(art.getVersion())) {
817 return true;
818 }
819 }
820
821 return false;
822 }
823
824
825
826
827
828
829
830
831 private DependencyNode getNode(ProjectBuildingRequest buildingRequest) throws MavenReportException {
832 try {
833 return dependencyCollectorBuilder.collectDependencyGraph(buildingRequest, filter);
834 } catch (DependencyCollectorBuilderException e) {
835 throw new MavenReportException("Could not build dependency tree: " + e.getMessage(), e);
836 }
837 }
838
839
840
841
842
843
844
845 private Set<Artifact> getAllDescendants(DependencyNode node) {
846 Set<Artifact> children = null;
847 if (node.getChildren() != null) {
848 children = new HashSet<>();
849 for (DependencyNode depNode : node.getChildren()) {
850 children.add(depNode.getArtifact());
851 Set<Artifact> subNodes = getAllDescendants(depNode);
852 if (subNodes != null) {
853 children.addAll(subNodes);
854 }
855 }
856 }
857 return children;
858 }
859
860 private int calculateConvergence(DependencyAnalyzeResult result) {
861 return (int) (((double) result.getDependencyCount() / (double) result.getArtifactCount()) * FULL_CONVERGENCE);
862 }
863
864
865
866
867 private static class ReverseDependencyLink {
868 private Dependency dependency;
869
870 protected MavenProject project;
871
872 ReverseDependencyLink(Dependency dependency, MavenProject project) {
873 this.dependency = dependency;
874 this.project = project;
875 }
876
877 public Dependency getDependency() {
878 return dependency;
879 }
880
881 public MavenProject getProject() {
882 return project;
883 }
884
885 @Override
886 public String toString() {
887 return project.getId();
888 }
889 }
890
891
892
893
894 static class DependencyNodeComparator implements Comparator<DependencyNode> {
895
896
897
898 public int compare(DependencyNode p1, DependencyNode p2) {
899 return p1.getArtifact().getId().compareTo(p2.getArtifact().getId());
900 }
901 }
902
903
904
905
906 private class DependencyAnalyzeResult {
907 Map<String, List<ReverseDependencyLink>> all;
908
909 List<ReverseDependencyLink> snapshots;
910
911 Map<String, List<ReverseDependencyLink>> conflicting;
912
913 public void setAll(Map<String, List<ReverseDependencyLink>> all) {
914 this.all = all;
915 }
916
917 public List<ReverseDependencyLink> getSnapshots() {
918 return snapshots;
919 }
920
921 public void setSnapshots(List<ReverseDependencyLink> snapshots) {
922 this.snapshots = snapshots;
923 }
924
925 public Map<String, List<ReverseDependencyLink>> getConflicting() {
926 return conflicting;
927 }
928
929 public void setConflicting(Map<String, List<ReverseDependencyLink>> conflicting) {
930 this.conflicting = conflicting;
931 }
932
933 public int getDependencyCount() {
934 return all.size();
935 }
936
937 public int getSnapshotCount() {
938 return this.snapshots.size();
939 }
940
941 public int getConflictingCount() {
942 return this.conflicting.size();
943 }
944
945 public int getArtifactCount() {
946 int artifactCount = 0;
947 for (List<ReverseDependencyLink> depList : this.all.values()) {
948 Map<String, List<ReverseDependencyLink>> artifactMap = getSortedUniqueArtifactMap(depList);
949 artifactCount += artifactMap.size();
950 }
951
952 return artifactCount;
953 }
954 }
955 }