1 package org.apache.maven.report.projectinfo.dependencies.renderer;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.lang.reflect.InvocationTargetException;
25 import java.net.URL;
26 import java.text.DecimalFormat;
27 import java.text.DecimalFormatSymbols;
28 import java.text.FieldPosition;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.Comparator;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Locale;
37 import java.util.Map;
38 import java.util.Set;
39 import java.util.SortedSet;
40 import java.util.TreeSet;
41
42 import org.apache.commons.lang.SystemUtils;
43 import org.apache.maven.artifact.Artifact;
44 import org.apache.maven.artifact.factory.ArtifactFactory;
45 import org.apache.maven.artifact.repository.ArtifactRepository;
46 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
47 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
48 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
49 import org.apache.maven.doxia.sink.Sink;
50 import org.apache.maven.doxia.sink.SinkEventAttributeSet;
51 import org.apache.maven.doxia.sink.SinkEventAttributes;
52 import org.apache.maven.doxia.util.HtmlTools;
53 import org.apache.maven.model.License;
54 import org.apache.maven.plugin.logging.Log;
55 import org.apache.maven.project.MavenProject;
56 import org.apache.maven.project.MavenProjectBuilder;
57 import org.apache.maven.project.ProjectBuildingException;
58 import org.apache.maven.report.projectinfo.AbstractProjectInfoRenderer;
59 import org.apache.maven.report.projectinfo.ProjectInfoReportUtils;
60 import org.apache.maven.report.projectinfo.dependencies.Dependencies;
61 import org.apache.maven.report.projectinfo.dependencies.DependenciesReportConfiguration;
62 import org.apache.maven.report.projectinfo.dependencies.RepositoryUtils;
63 import org.apache.maven.settings.Settings;
64 import org.apache.maven.shared.dependency.graph.DependencyNode;
65 import org.apache.maven.shared.jar.JarData;
66 import org.codehaus.plexus.i18n.I18N;
67 import org.codehaus.plexus.util.StringUtils;
68
69
70
71
72
73
74
75 public class DependenciesRenderer
76 extends AbstractProjectInfoRenderer
77 {
78
79 private static final String IMG_INFO_URL = "./images/icon_info_sml.gif";
80
81
82 private static final String IMG_CLOSE_URL = "./images/close.gif";
83
84
85 protected static final DecimalFormat DEFAULT_DECIMAL_FORMAT = new DecimalFormat( "###0" );
86
87 private static final Set<String> JAR_SUBTYPE;
88
89
90
91
92 private static final String JAVASCRIPT;
93
94 private final DependencyNode dependencyNode;
95
96 private final Dependencies dependencies;
97
98 private final DependenciesReportConfiguration configuration;
99
100 private final Log log;
101
102 private final Settings settings;
103
104 private final RepositoryUtils repoUtils;
105
106
107 private final DecimalFormat fileLengthDecimalFormat;
108
109
110
111
112 private int section;
113
114
115 private int idCounter = 0;
116
117
118
119
120 private Map<String, Object> licenseMap = new HashMap<String, Object>()
121 {
122 private static final long serialVersionUID = 1L;
123
124
125 public Object put( String key, Object value )
126 {
127
128 @SuppressWarnings( "unchecked" )
129 SortedSet<Object> valueList = (SortedSet<Object>) get( key );
130 if ( valueList == null )
131 {
132 valueList = new TreeSet<Object>();
133 }
134 valueList.add( value );
135 return super.put( key, valueList );
136 }
137 };
138
139 private final ArtifactFactory artifactFactory;
140
141 private final MavenProjectBuilder mavenProjectBuilder;
142
143 private final List<ArtifactRepository> remoteRepositories;
144
145 private final ArtifactRepository localRepository;
146
147 static
148 {
149 Set<String> jarSubtype = new HashSet<String>();
150 jarSubtype.add( "jar" );
151 jarSubtype.add( "war" );
152 jarSubtype.add( "ear" );
153 jarSubtype.add( "sar" );
154 jarSubtype.add( "rar" );
155 jarSubtype.add( "par" );
156 jarSubtype.add( "ejb" );
157 JAR_SUBTYPE = Collections.unmodifiableSet( jarSubtype );
158
159 JAVASCRIPT =
160 "<script language=\"javascript\" type=\"text/javascript\">" + SystemUtils.LINE_SEPARATOR
161 + " function toggleDependencyDetail( divId, imgId )" + SystemUtils.LINE_SEPARATOR + " {"
162 + SystemUtils.LINE_SEPARATOR + " var div = document.getElementById( divId );"
163 + SystemUtils.LINE_SEPARATOR + " var img = document.getElementById( imgId );"
164 + SystemUtils.LINE_SEPARATOR + " if( div.style.display == '' )" + SystemUtils.LINE_SEPARATOR
165 + " {" + SystemUtils.LINE_SEPARATOR + " div.style.display = 'none';"
166 + SystemUtils.LINE_SEPARATOR + " img.src='" + IMG_INFO_URL + "';" + SystemUtils.LINE_SEPARATOR
167 + " }" + SystemUtils.LINE_SEPARATOR + " else" + SystemUtils.LINE_SEPARATOR + " {"
168 + SystemUtils.LINE_SEPARATOR + " div.style.display = '';" + SystemUtils.LINE_SEPARATOR
169 + " img.src='" + IMG_CLOSE_URL + "';" + SystemUtils.LINE_SEPARATOR + " }"
170 + SystemUtils.LINE_SEPARATOR + " }" + SystemUtils.LINE_SEPARATOR + "</script>"
171 + SystemUtils.LINE_SEPARATOR;
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191 public DependenciesRenderer( Sink sink, Locale locale, I18N i18n, Log log, Settings settings,
192 Dependencies dependencies, DependencyNode dependencyTreeNode,
193 DependenciesReportConfiguration config, RepositoryUtils repoUtils,
194 ArtifactFactory artifactFactory, MavenProjectBuilder mavenProjectBuilder,
195 List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository )
196 {
197 super( sink, i18n, locale );
198
199 this.log = log;
200 this.settings = settings;
201 this.dependencies = dependencies;
202 this.dependencyNode = dependencyTreeNode;
203 this.repoUtils = repoUtils;
204 this.configuration = config;
205 this.artifactFactory = artifactFactory;
206 this.mavenProjectBuilder = mavenProjectBuilder;
207 this.remoteRepositories = remoteRepositories;
208 this.localRepository = localRepository;
209
210
211 DEFAULT_DECIMAL_FORMAT.setDecimalFormatSymbols( new DecimalFormatSymbols( locale ) );
212
213 this.fileLengthDecimalFormat = new FileDecimalFormat( i18n, locale );
214 this.fileLengthDecimalFormat.setDecimalFormatSymbols( new DecimalFormatSymbols( locale ) );
215 }
216
217 @Override
218 protected String getI18Nsection()
219 {
220 return "dependencies";
221 }
222
223
224
225
226
227 @Override
228 public void renderBody()
229 {
230
231
232 if ( !dependencies.hasDependencies() )
233 {
234 startSection( getTitle() );
235
236 paragraph( getI18nString( "nolist" ) );
237
238 endSection();
239
240 return;
241 }
242
243
244 renderSectionProjectDependencies();
245
246
247 renderSectionProjectTransitiveDependencies();
248
249
250 renderSectionProjectDependencyGraph();
251
252
253 renderSectionDependencyLicenseListing();
254
255 if ( configuration.getDependencyDetailsEnabled() )
256 {
257
258 renderSectionDependencyFileDetails();
259 }
260
261 if ( configuration.getDependencyLocationsEnabled() )
262 {
263
264 renderSectionDependencyRepositoryLocations();
265 }
266 }
267
268
269
270
271
272
273
274
275 protected void startSection( String name )
276 {
277 startSection( name, name );
278 }
279
280
281
282
283
284
285
286
287 protected void startSection( String anchor, String name )
288 {
289 section = section + 1;
290
291 super.sink.anchor( HtmlTools.encodeId( anchor ) );
292 super.sink.anchor_();
293
294 switch ( section )
295 {
296 case 1:
297 sink.section1();
298 sink.sectionTitle1();
299 break;
300 case 2:
301 sink.section2();
302 sink.sectionTitle2();
303 break;
304 case 3:
305 sink.section3();
306 sink.sectionTitle3();
307 break;
308 case 4:
309 sink.section4();
310 sink.sectionTitle4();
311 break;
312 case 5:
313 sink.section5();
314 sink.sectionTitle5();
315 break;
316
317 default:
318
319 break;
320 }
321
322 text( name );
323
324 switch ( section )
325 {
326 case 1:
327 sink.sectionTitle1_();
328 break;
329 case 2:
330 sink.sectionTitle2_();
331 break;
332 case 3:
333 sink.sectionTitle3_();
334 break;
335 case 4:
336 sink.sectionTitle4_();
337 break;
338 case 5:
339 sink.sectionTitle5_();
340 break;
341
342 default:
343
344 break;
345 }
346 }
347
348
349
350
351 protected void endSection()
352 {
353 switch ( section )
354 {
355 case 1:
356 sink.section1_();
357 break;
358 case 2:
359 sink.section2_();
360 break;
361 case 3:
362 sink.section3_();
363 break;
364 case 4:
365 sink.section4_();
366 break;
367 case 5:
368 sink.section5_();
369 break;
370
371 default:
372
373 break;
374 }
375
376 section = section - 1;
377
378 if ( section < 0 )
379 {
380 throw new IllegalStateException( "Too many closing sections" );
381 }
382 }
383
384
385
386
387
388
389
390
391
392
393
394 private String[] getDependencyTableHeader( boolean withClassifier, boolean withOptional )
395 {
396 String groupId = getI18nString( "column.groupId" );
397 String artifactId = getI18nString( "column.artifactId" );
398 String version = getI18nString( "column.version" );
399 String classifier = getI18nString( "column.classifier" );
400 String type = getI18nString( "column.type" );
401 String license = getI18nString( "column.license" );
402 String optional = getI18nString( "column.optional" );
403
404 if ( withClassifier )
405 {
406 if ( withOptional )
407 {
408 return new String[] { groupId, artifactId, version, classifier, type, license, optional };
409 }
410
411 return new String[] { groupId, artifactId, version, classifier, type, license };
412 }
413
414 if ( withOptional )
415 {
416 return new String[] { groupId, artifactId, version, type, license, optional };
417 }
418
419 return new String[] { groupId, artifactId, version, type, license };
420 }
421
422 private void renderSectionProjectDependencies()
423 {
424 startSection( getTitle() );
425
426
427 Map<String, List<Artifact>> dependenciesByScope = dependencies.getDependenciesByScope( false );
428
429 renderDependenciesForAllScopes( dependenciesByScope, false );
430
431 endSection();
432 }
433
434
435
436
437
438
439
440
441
442
443 private void renderDependenciesForAllScopes( Map<String, List<Artifact>> dependenciesByScope, boolean isTransitive )
444 {
445 renderDependenciesForScope( Artifact.SCOPE_COMPILE, dependenciesByScope.get( Artifact.SCOPE_COMPILE ),
446 isTransitive );
447 renderDependenciesForScope( Artifact.SCOPE_RUNTIME, dependenciesByScope.get( Artifact.SCOPE_RUNTIME ),
448 isTransitive );
449 renderDependenciesForScope( Artifact.SCOPE_TEST, dependenciesByScope.get( Artifact.SCOPE_TEST ), isTransitive );
450 renderDependenciesForScope( Artifact.SCOPE_PROVIDED, dependenciesByScope.get( Artifact.SCOPE_PROVIDED ),
451 isTransitive );
452 renderDependenciesForScope( Artifact.SCOPE_SYSTEM, dependenciesByScope.get( Artifact.SCOPE_SYSTEM ),
453 isTransitive );
454 }
455
456 private void renderSectionProjectTransitiveDependencies()
457 {
458 Map<String, List<Artifact>> dependenciesByScope = dependencies.getDependenciesByScope( true );
459
460 startSection( getI18nString( "transitive.title" ) );
461
462 if ( dependenciesByScope.values().isEmpty() )
463 {
464 paragraph( getI18nString( "transitive.nolist" ) );
465 }
466 else
467 {
468 paragraph( getI18nString( "transitive.intro" ) );
469
470 renderDependenciesForAllScopes( dependenciesByScope, true );
471 }
472
473 endSection();
474 }
475
476 private void renderSectionProjectDependencyGraph()
477 {
478 startSection( getI18nString( "graph.title" ) );
479
480
481 renderSectionDependencyTree();
482
483 endSection();
484 }
485
486 private void renderSectionDependencyTree()
487 {
488 sink.rawText( JAVASCRIPT );
489
490
491 startSection( getI18nString( "graph.tree.title" ) );
492
493 sink.list();
494 printDependencyListing( dependencyNode );
495 sink.list_();
496
497 endSection();
498 }
499
500 private void renderSectionDependencyFileDetails()
501 {
502 startSection( getI18nString( "file.details.title" ) );
503
504 List<Artifact> alldeps = dependencies.getAllDependencies();
505 Collections.sort( alldeps, getArtifactComparator() );
506
507
508 String filename = getI18nString( "file.details.column.file" );
509 String size = getI18nString( "file.details.column.size" );
510 String entries = getI18nString( "file.details.column.entries" );
511 String classes = getI18nString( "file.details.column.classes" );
512 String packages = getI18nString( "file.details.column.packages" );
513 String javaVersion = getI18nString( "file.details.column.javaVersion" );
514 String debugInformation = getI18nString( "file.details.column.debuginformation" );
515 String debugInformationTitle = getI18nString( "file.details.columntitle.debuginformation" );
516 String debugInformationCellYes = getI18nString( "file.details.cell.debuginformation.yes" );
517 String debugInformationCellNo = getI18nString( "file.details.cell.debuginformation.no" );
518 String sealed = getI18nString( "file.details.column.sealed" );
519
520 int[] justification =
521 new int[] { Sink.JUSTIFY_LEFT, Sink.JUSTIFY_RIGHT, Sink.JUSTIFY_RIGHT, Sink.JUSTIFY_RIGHT,
522 Sink.JUSTIFY_RIGHT, Sink.JUSTIFY_CENTER, Sink.JUSTIFY_CENTER, Sink.JUSTIFY_CENTER };
523
524 startTable( justification, false );
525
526 TotalCell totaldeps = new TotalCell( DEFAULT_DECIMAL_FORMAT );
527 TotalCell totaldepsize = new TotalCell( fileLengthDecimalFormat );
528 TotalCell totalentries = new TotalCell( DEFAULT_DECIMAL_FORMAT );
529 TotalCell totalclasses = new TotalCell( DEFAULT_DECIMAL_FORMAT );
530 TotalCell totalpackages = new TotalCell( DEFAULT_DECIMAL_FORMAT );
531 double highestJavaVersion = 0.0;
532 TotalCell totalDebugInformation = new TotalCell( DEFAULT_DECIMAL_FORMAT );
533 TotalCell totalsealed = new TotalCell( DEFAULT_DECIMAL_FORMAT );
534
535 boolean hasSealed = hasSealed( alldeps );
536
537
538 String[] tableHeader;
539 String[] tableHeaderTitles;
540 if ( hasSealed )
541 {
542 tableHeader = new String[] { filename, size, entries, classes, packages, javaVersion, debugInformation,
543 sealed };
544 tableHeaderTitles = new String[] { null, null, null, null, null, null, debugInformationTitle, null };
545 }
546 else
547 {
548 tableHeader = new String[] { filename, size, entries, classes, packages, javaVersion, debugInformation };
549 tableHeaderTitles = new String[] { null, null, null, null, null, null, debugInformationTitle };
550 }
551 tableHeader( tableHeader, tableHeaderTitles );
552
553
554 for ( Artifact artifact : alldeps )
555 {
556 if ( artifact.getFile() == null )
557 {
558 log.warn( "Artifact " + artifact.getId() + " has no file,"
559 + " won't be listed in dependency files details." );
560 continue;
561 }
562
563 File artifactFile = dependencies.getFile( artifact );
564
565 totaldeps.incrementTotal( artifact.getScope() );
566 totaldepsize.addTotal( artifactFile.length(), artifact.getScope() );
567
568 if ( JAR_SUBTYPE.contains( artifact.getType().toLowerCase() ) )
569 {
570 try
571 {
572 JarData jarDetails = dependencies.getJarDependencyDetails( artifact );
573
574 String debugInformationCellValue = debugInformationCellNo;
575 if ( jarDetails.isDebugPresent() )
576 {
577 debugInformationCellValue = debugInformationCellYes;
578 totalDebugInformation.incrementTotal( artifact.getScope() );
579 }
580
581 totalentries.addTotal( jarDetails.getNumEntries(), artifact.getScope() );
582 totalclasses.addTotal( jarDetails.getNumClasses(), artifact.getScope() );
583 totalpackages.addTotal( jarDetails.getNumPackages(), artifact.getScope() );
584
585 try
586 {
587 if ( jarDetails.getJdkRevision() != null )
588 {
589 highestJavaVersion = Math.max( highestJavaVersion,
590 Double.parseDouble( jarDetails.getJdkRevision() ) );
591 }
592 }
593 catch ( NumberFormatException e )
594 {
595
596 }
597
598 String sealedstr = "";
599 if ( jarDetails.isSealed() )
600 {
601 sealedstr = "sealed";
602 totalsealed.incrementTotal( artifact.getScope() );
603 }
604
605 String name = artifactFile.getName();
606 String fileLength = fileLengthDecimalFormat.format( artifactFile.length() );
607
608 if ( artifactFile.isDirectory() )
609 {
610 File parent = artifactFile.getParentFile();
611 name = parent.getParentFile().getName() + '/' + parent.getName() + '/' + artifactFile.getName();
612 fileLength = "-";
613 }
614
615 tableRow( hasSealed,
616 new String[] { name, fileLength,
617 DEFAULT_DECIMAL_FORMAT.format( jarDetails.getNumEntries() ),
618 DEFAULT_DECIMAL_FORMAT.format( jarDetails.getNumClasses() ),
619 DEFAULT_DECIMAL_FORMAT.format( jarDetails.getNumPackages() ),
620 jarDetails.getJdkRevision(), debugInformationCellValue, sealedstr } );
621 }
622 catch ( IOException e )
623 {
624 createExceptionInfoTableRow( artifact, artifactFile, e, hasSealed );
625 }
626 }
627 else
628 {
629 tableRow( hasSealed,
630 new String[] { artifactFile.getName(),
631 fileLengthDecimalFormat.format( artifactFile.length() ), "", "", "", "", "", "" } );
632 }
633 }
634
635
636 tableHeader[0] = getI18nString( "file.details.total" );
637 tableHeader( tableHeader );
638
639 justification[0] = Sink.JUSTIFY_RIGHT;
640 justification[6] = Sink.JUSTIFY_RIGHT;
641
642 for ( int i = -1; i < TotalCell.SCOPES_COUNT; i++ )
643 {
644 if ( totaldeps.getTotal( i ) > 0 )
645 {
646 tableRow( hasSealed,
647 new String[] { totaldeps.getTotalString( i ), totaldepsize.getTotalString( i ),
648 totalentries.getTotalString( i ), totalclasses.getTotalString( i ),
649 totalpackages.getTotalString( i ), ( i < 0 ) ? String.valueOf( highestJavaVersion ) : "",
650 totalDebugInformation.getTotalString( i ), totalsealed.getTotalString( i ) } );
651 }
652 }
653
654 endTable();
655 endSection();
656 }
657
658
659 private void tableHeader( String[] content, String[] titles )
660 {
661 sink.tableRow();
662
663 if ( content != null )
664 {
665 if ( titles != null && content.length != titles.length )
666 {
667
668 throw new IllegalArgumentException( "Length of title array must equal the length of the content array" );
669
670 }
671
672 for ( int i = 0; i < content.length; i++ )
673 {
674 if ( titles != null )
675 {
676 tableHeaderCell( content[i], titles[i] );
677 }
678 else
679 {
680 tableHeaderCell( content[i] );
681 }
682 }
683 }
684
685 sink.tableRow_();
686 }
687
688 private void tableHeaderCell( String text, String title )
689 {
690 if ( title != null )
691 {
692 SinkEventAttributes attributes = new SinkEventAttributeSet( SinkEventAttributes.TITLE, title );
693 sink.tableHeaderCell( attributes );
694 }
695 else
696 {
697 sink.tableHeaderCell();
698 }
699
700 text( text );
701
702 sink.tableHeaderCell_();
703 }
704
705 private void tableRow( boolean fullRow, String[] content )
706 {
707 sink.tableRow();
708
709 int count = fullRow ? content.length : ( content.length - 1 );
710
711 for ( int i = 0; i < count; i++ )
712 {
713 tableCell( content[i] );
714 }
715
716 sink.tableRow_();
717 }
718
719 private void createExceptionInfoTableRow( Artifact artifact, File artifactFile, Exception e, boolean hasSealed )
720 {
721 tableRow( hasSealed, new String[] { artifact.getId(), artifactFile.getAbsolutePath(), e.getMessage(), "", "",
722 "", "", "" } );
723 }
724
725 private void populateRepositoryMap( Map<String, ArtifactRepository> repos, List<ArtifactRepository> rowRepos )
726 {
727 for ( ArtifactRepository repo : rowRepos )
728 {
729 repos.put( repo.getId(), repo );
730 }
731 }
732
733 private void blacklistRepositoryMap( Map<String, ArtifactRepository> repos, List<String> repoUrlBlackListed )
734 {
735 for ( ArtifactRepository repo : repos.values() )
736 {
737
738 if ( repo.isBlacklisted() )
739 {
740 repoUrlBlackListed.add( repo.getUrl() );
741 }
742 else
743 {
744 if ( repoUrlBlackListed.contains( repo.getUrl() ) )
745 {
746 repo.setBlacklisted( true );
747 }
748 else
749 {
750 try
751 {
752 URL repoUrl = new URL( repo.getUrl() );
753 if ( ProjectInfoReportUtils.getContent( repoUrl, settings ) == null )
754 {
755 log.warn( "The repository url '" + repoUrl + "' has no stream - Repository '"
756 + repo.getId() + "' will be blacklisted." );
757 repo.setBlacklisted( true );
758 repoUrlBlackListed.add( repo.getUrl() );
759 }
760 }
761 catch ( IOException e )
762 {
763 log.warn( "The repository url '" + repo.getUrl() + "' is invalid - Repository '" + repo.getId()
764 + "' will be blacklisted." );
765 repo.setBlacklisted( true );
766 repoUrlBlackListed.add( repo.getUrl() );
767 }
768 }
769 }
770 }
771 }
772
773 @SuppressWarnings( "unchecked" )
774 private void renderSectionDependencyRepositoryLocations()
775 {
776 startSection( getI18nString( "repo.locations.title" ) );
777
778
779 List<Artifact> alldeps = dependencies.getAllDependencies();
780 Collections.sort( alldeps, getArtifactComparator() );
781
782
783 Map<String, ArtifactRepository> repoMap = new HashMap<String, ArtifactRepository>();
784
785 populateRepositoryMap( repoMap, repoUtils.getRemoteArtifactRepositories() );
786 for ( Artifact artifact : alldeps )
787 {
788 try
789 {
790 MavenProject artifactProject = repoUtils.getMavenProjectFromRepository( artifact );
791 populateRepositoryMap( repoMap, artifactProject.getRemoteArtifactRepositories() );
792 }
793 catch ( ProjectBuildingException e )
794 {
795 log.warn( "Unable to create Maven project from repository for artifact " + artifact.getId(), e );
796 }
797 }
798
799 List<String> repoUrlBlackListed = new ArrayList<String>();
800 blacklistRepositoryMap( repoMap, repoUrlBlackListed );
801
802
803
804 printRepositories( repoMap, repoUrlBlackListed );
805
806
807
808 printArtifactsLocations( repoMap, repoUrlBlackListed, alldeps );
809
810 endSection();
811 }
812
813 private void renderSectionDependencyLicenseListing()
814 {
815 startSection( getI18nString( "graph.tables.licenses" ) );
816 printGroupedLicenses();
817 endSection();
818 }
819
820 private void renderDependenciesForScope( String scope, List<Artifact> artifacts, boolean isTransitive )
821 {
822 if ( artifacts != null )
823 {
824 boolean withClassifier = hasClassifier( artifacts );
825 boolean withOptional = hasOptional( artifacts );
826 String[] tableHeader = getDependencyTableHeader( withClassifier, withOptional );
827
828
829 Collections.sort( artifacts, getArtifactComparator() );
830
831 String anchorByScope =
832 ( isTransitive ? getI18nString( "transitive.title" ) + "_" + scope : getI18nString( "title" ) + "_"
833 + scope );
834 startSection( anchorByScope, scope );
835
836 paragraph( getI18nString( "intro." + scope ) );
837
838 startTable();
839 tableHeader( tableHeader );
840 for ( Artifact artifact : artifacts )
841 {
842 renderArtifactRow( artifact, withClassifier, withOptional );
843 }
844 endTable();
845
846 endSection();
847 }
848 }
849
850 private Comparator<Artifact> getArtifactComparator()
851 {
852 return new Comparator<Artifact>()
853 {
854 public int compare( Artifact a1, Artifact a2 )
855 {
856
857 if ( a1.isOptional() && !a2.isOptional() )
858 {
859 return +1;
860 }
861 else if ( !a1.isOptional() && a2.isOptional() )
862 {
863 return -1;
864 }
865 else
866 {
867 return a1.compareTo( a2 );
868 }
869 }
870 };
871 }
872
873
874
875
876
877
878
879 private void renderArtifactRow( Artifact artifact, boolean withClassifier, boolean withOptional )
880 {
881 String isOptional =
882 artifact.isOptional() ? getI18nString( "column.isOptional" ) : getI18nString( "column.isNotOptional" );
883
884 String url =
885 ProjectInfoReportUtils.getArtifactUrl( artifactFactory, artifact, mavenProjectBuilder, remoteRepositories,
886 localRepository );
887 String artifactIdCell = ProjectInfoReportUtils.getArtifactIdCell( artifact.getArtifactId(), url );
888
889 MavenProject artifactProject;
890 StringBuilder sb = new StringBuilder();
891 try
892 {
893 artifactProject = repoUtils.getMavenProjectFromRepository( artifact );
894 @SuppressWarnings( "unchecked" )
895 List<License> licenses = artifactProject.getLicenses();
896 for ( License license : licenses )
897 {
898 sb.append( ProjectInfoReportUtils.getArtifactIdCell( license.getName(), license.getUrl() ) );
899 }
900 }
901 catch ( ProjectBuildingException e )
902 {
903 log.warn( "Unable to create Maven project from repository.", e );
904 }
905
906 String content[];
907 if ( withClassifier )
908 {
909 content =
910 new String[] { artifact.getGroupId(), artifactIdCell, artifact.getVersion(), artifact.getClassifier(),
911 artifact.getType(), sb.toString(), isOptional };
912 }
913 else
914 {
915 content =
916 new String[] { artifact.getGroupId(), artifactIdCell, artifact.getVersion(), artifact.getType(),
917 sb.toString(), isOptional };
918 }
919
920 tableRow( withOptional, content );
921 }
922
923 private void printDependencyListing( DependencyNode node )
924 {
925 Artifact artifact = node.getArtifact();
926 String id = artifact.getId();
927 String dependencyDetailId = "_dep" + idCounter++;
928 String imgId = "_img" + idCounter++;
929
930 sink.listItem();
931
932 sink.text( id + ( StringUtils.isNotEmpty( artifact.getScope() ) ? " (" + artifact.getScope() + ") " : " " ) );
933 sink.rawText( "<img id=\"" + imgId + "\" src=\"" + IMG_INFO_URL
934 + "\" alt=\"Information\" onclick=\"toggleDependencyDetail( '" + dependencyDetailId + "', '" + imgId
935 + "' );\" style=\"cursor: pointer;vertical-align:text-bottom;\"></img>" );
936
937 printDescriptionsAndURLs( node, dependencyDetailId );
938
939 if ( !node.getChildren().isEmpty() )
940 {
941 boolean toBeIncluded = false;
942 List<DependencyNode> subList = new ArrayList<DependencyNode>();
943 for ( DependencyNode dep : node.getChildren() )
944 {
945 if ( dependencies.getAllDependencies().contains( dep.getArtifact() ) )
946 {
947 subList.add( dep );
948 toBeIncluded = true;
949 }
950 }
951
952 if ( toBeIncluded )
953 {
954 sink.list();
955 for ( DependencyNode dep : subList )
956 {
957 printDependencyListing( dep );
958 }
959 sink.list_();
960 }
961 }
962
963 sink.listItem_();
964 }
965
966 private void printDescriptionsAndURLs( DependencyNode node, String uid )
967 {
968 Artifact artifact = node.getArtifact();
969 String id = artifact.getId();
970 String unknownLicenseMessage = getI18nString( "graph.tables.unknown" );
971
972 sink.rawText( "<div id=\"" + uid + "\" style=\"display:none\">" );
973
974 sink.table();
975
976 if ( !Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
977 {
978 try
979 {
980 MavenProject artifactProject = repoUtils.getMavenProjectFromRepository( artifact );
981 String artifactDescription = artifactProject.getDescription();
982 String artifactUrl = artifactProject.getUrl();
983 String artifactName = artifactProject.getName();
984 @SuppressWarnings( "unchecked" )
985 List<License> licenses = artifactProject.getLicenses();
986
987 sink.tableRow();
988 sink.tableHeaderCell();
989 sink.text( artifactName );
990 sink.tableHeaderCell_();
991 sink.tableRow_();
992
993 sink.tableRow();
994 sink.tableCell();
995
996 sink.paragraph();
997 sink.bold();
998 sink.text( getI18nString( "column.description" ) + ": " );
999 sink.bold_();
1000 if ( StringUtils.isNotEmpty( artifactDescription ) )
1001 {
1002 sink.text( artifactDescription );
1003 }
1004 else
1005 {
1006 sink.text( getI18nString( "index", "nodescription" ) );
1007 }
1008 sink.paragraph_();
1009
1010 if ( StringUtils.isNotEmpty( artifactUrl ) )
1011 {
1012 sink.paragraph();
1013 sink.bold();
1014 sink.text( getI18nString( "column.url" ) + ": " );
1015 sink.bold_();
1016 if ( ProjectInfoReportUtils.isArtifactUrlValid( artifactUrl ) )
1017 {
1018 sink.link( artifactUrl );
1019 sink.text( artifactUrl );
1020 sink.link_();
1021 }
1022 else
1023 {
1024 sink.text( artifactUrl );
1025 }
1026 sink.paragraph_();
1027 }
1028
1029 sink.paragraph();
1030 sink.bold();
1031 sink.text( getI18nString( "license", "title" ) + ": " );
1032 sink.bold_();
1033 if ( !licenses.isEmpty() )
1034 {
1035
1036 for ( Iterator<License> it = licenses.iterator(); it.hasNext(); )
1037 {
1038 License license = it.next();
1039
1040 String licenseName = license.getName();
1041 if ( StringUtils.isEmpty( licenseName ) )
1042 {
1043 licenseName = getI18nString( "unnamed" );
1044 }
1045
1046 String licenseUrl = license.getUrl();
1047
1048 if ( licenseUrl != null )
1049 {
1050 sink.link( licenseUrl );
1051 }
1052 sink.text( licenseName );
1053
1054 if ( licenseUrl != null )
1055 {
1056 sink.link_();
1057 }
1058
1059 if ( it.hasNext() )
1060 {
1061 sink.text( ", " );
1062 }
1063
1064 licenseMap.put( licenseName, artifactName );
1065 }
1066 }
1067 else
1068 {
1069 sink.text( getI18nString( "license", "nolicense" ) );
1070
1071 licenseMap.put( unknownLicenseMessage, artifactName );
1072 }
1073 sink.paragraph_();
1074 }
1075 catch ( ProjectBuildingException e )
1076 {
1077 log.warn( "Unable to create Maven project from repository for artifact " + artifact.getId(), e );
1078 }
1079 }
1080 else
1081 {
1082 sink.tableRow();
1083 sink.tableHeaderCell();
1084 sink.text( id );
1085 sink.tableHeaderCell_();
1086 sink.tableRow_();
1087
1088 sink.tableRow();
1089 sink.tableCell();
1090
1091 sink.paragraph();
1092 sink.bold();
1093 sink.text( getI18nString( "column.description" ) + ": " );
1094 sink.bold_();
1095 sink.text( getI18nString( "index", "nodescription" ) );
1096 sink.paragraph_();
1097
1098 if ( artifact.getFile() != null )
1099 {
1100 sink.paragraph();
1101 sink.bold();
1102 sink.text( getI18nString( "column.url" ) + ": " );
1103 sink.bold_();
1104 sink.text( artifact.getFile().getAbsolutePath() );
1105 sink.paragraph_();
1106 }
1107 }
1108
1109 sink.tableCell_();
1110 sink.tableRow_();
1111
1112 sink.table_();
1113
1114 sink.rawText( "</div>" );
1115 }
1116
1117 private void printGroupedLicenses()
1118 {
1119 for ( Map.Entry<String, Object> entry : licenseMap.entrySet() )
1120 {
1121 String licenseName = entry.getKey();
1122 if ( StringUtils.isEmpty( licenseName ) )
1123 {
1124 licenseName = getI18nString( "unnamed" );
1125 }
1126
1127 sink.paragraph();
1128 sink.bold();
1129 sink.text( licenseName );
1130 sink.text( ": " );
1131 sink.bold_();
1132
1133 @SuppressWarnings( "unchecked" )
1134 SortedSet<String> projects = (SortedSet<String>) entry.getValue();
1135
1136 for ( Iterator<String> iterator = projects.iterator(); iterator.hasNext(); )
1137 {
1138 String projectName = iterator.next();
1139 sink.text( projectName );
1140 if ( iterator.hasNext() )
1141 {
1142 sink.text( ", " );
1143 }
1144 }
1145
1146 sink.paragraph_();
1147 }
1148 }
1149
1150 private void printRepositories( Map<String, ArtifactRepository> repoMap, List<String> repoUrlBlackListed )
1151 {
1152
1153 String repoid = getI18nString( "repo.locations.column.repoid" );
1154 String url = getI18nString( "repo.locations.column.url" );
1155 String release = getI18nString( "repo.locations.column.release" );
1156 String snapshot = getI18nString( "repo.locations.column.snapshot" );
1157 String blacklisted = getI18nString( "repo.locations.column.blacklisted" );
1158 String releaseEnabled = getI18nString( "repo.locations.cell.release.enabled" );
1159 String releaseDisabled = getI18nString( "repo.locations.cell.release.disabled" );
1160 String snapshotEnabled = getI18nString( "repo.locations.cell.snapshot.enabled" );
1161 String snapshotDisabled = getI18nString( "repo.locations.cell.snapshot.disabled" );
1162 String blacklistedEnabled = getI18nString( "repo.locations.cell.blacklisted.enabled" );
1163 String blacklistedDisabled = getI18nString( "repo.locations.cell.blacklisted.disabled" );
1164
1165
1166
1167 String[] tableHeader;
1168 int[] justificationRepo;
1169 if ( repoUrlBlackListed.isEmpty() )
1170 {
1171 tableHeader = new String[] { repoid, url, release, snapshot };
1172 justificationRepo =
1173 new int[] { Sink.JUSTIFY_LEFT, Sink.JUSTIFY_LEFT, Sink.JUSTIFY_CENTER, Sink.JUSTIFY_CENTER };
1174 }
1175 else
1176 {
1177 tableHeader = new String[] { repoid, url, release, snapshot, blacklisted };
1178 justificationRepo =
1179 new int[] { Sink.JUSTIFY_LEFT, Sink.JUSTIFY_LEFT, Sink.JUSTIFY_CENTER, Sink.JUSTIFY_CENTER,
1180 Sink.JUSTIFY_CENTER };
1181 }
1182
1183 startTable( justificationRepo, false );
1184
1185 tableHeader( tableHeader );
1186
1187
1188
1189 for ( ArtifactRepository repo : repoMap.values() )
1190 {
1191 List<ArtifactRepository> mirroredRepos = getMirroredRepositories( repo );
1192
1193 sink.tableRow();
1194 sink.tableCell();
1195 boolean addLineBreak = false;
1196 for ( ArtifactRepository r : mirroredRepos )
1197 {
1198 if ( addLineBreak )
1199 {
1200 sink.lineBreak();
1201 }
1202 addLineBreak = true;
1203 sink.text( r.getId() );
1204 }
1205 sink.tableCell_();
1206
1207 sink.tableCell();
1208 addLineBreak = false;
1209 for ( ArtifactRepository r : mirroredRepos )
1210 {
1211 if ( addLineBreak )
1212 {
1213 sink.lineBreak();
1214 }
1215 addLineBreak = true;
1216 if ( repo.isBlacklisted() )
1217 {
1218 sink.text( r.getUrl() );
1219 }
1220 else
1221 {
1222 sink.link( r.getUrl() );
1223 sink.text( r.getUrl() );
1224 sink.link_();
1225 }
1226 }
1227 sink.tableCell_();
1228
1229 ArtifactRepositoryPolicy releasePolicy = repo.getReleases();
1230 tableCell( releasePolicy.isEnabled() ? releaseEnabled : releaseDisabled );
1231
1232 ArtifactRepositoryPolicy snapshotPolicy = repo.getSnapshots();
1233 tableCell( snapshotPolicy.isEnabled() ? snapshotEnabled : snapshotDisabled );
1234
1235 if ( !repoUrlBlackListed.isEmpty() )
1236 {
1237 tableCell( repoUrlBlackListed.contains( repo.getUrl() ) ? blacklistedEnabled : blacklistedDisabled );
1238 }
1239
1240 sink.tableRow_();
1241 }
1242
1243 endTable();
1244 }
1245
1246 private Object invoke( Object object, String method )
1247 throws IllegalAccessException, InvocationTargetException, NoSuchMethodException
1248 {
1249 return object.getClass().getMethod( method ).invoke( object );
1250 }
1251
1252
1253
1254
1255
1256
1257
1258 private List<ArtifactRepository> getMirroredRepositories( ArtifactRepository repo )
1259 {
1260 try
1261 {
1262 @SuppressWarnings( "unchecked" )
1263 List<ArtifactRepository> mirroredRepos =
1264 (List<ArtifactRepository>) invoke( repo, "getMirroredRepositories" );
1265
1266 if ( ( mirroredRepos != null ) && ( !mirroredRepos.isEmpty() ) )
1267 {
1268 return mirroredRepos;
1269 }
1270 }
1271 catch ( IllegalArgumentException e )
1272 {
1273
1274 }
1275 catch ( SecurityException e )
1276 {
1277
1278 }
1279 catch ( IllegalAccessException e )
1280 {
1281
1282 }
1283 catch ( InvocationTargetException e )
1284 {
1285
1286 }
1287 catch ( NoSuchMethodException e )
1288 {
1289
1290 }
1291
1292 return Collections.singletonList( repo );
1293 }
1294
1295 private void printArtifactsLocations( Map<String, ArtifactRepository> repoMap, List<String> repoUrlBlackListed,
1296 List<Artifact> alldeps )
1297 {
1298
1299 String artifact = getI18nString( "repo.locations.column.artifact" );
1300
1301 sink.paragraph();
1302 sink.text( getI18nString( "repo.locations.artifact.breakdown" ) );
1303 sink.paragraph_();
1304
1305 List<String> repoIdList = new ArrayList<String>();
1306
1307 for ( Map.Entry<String, ArtifactRepository> entry : repoMap.entrySet() )
1308 {
1309 String repokey = entry.getKey();
1310 ArtifactRepository repo = entry.getValue();
1311 if ( !( repo.isBlacklisted() || repoUrlBlackListed.contains( repo.getUrl() ) ) )
1312 {
1313 repoIdList.add( repokey );
1314 }
1315 }
1316
1317 String[] tableHeader = new String[repoIdList.size() + 1];
1318 int[] justificationRepo = new int[repoIdList.size() + 1];
1319
1320 tableHeader[0] = artifact;
1321 justificationRepo[0] = Sink.JUSTIFY_LEFT;
1322
1323 int idnum = 1;
1324 for ( String id : repoIdList )
1325 {
1326 tableHeader[idnum] = id;
1327 justificationRepo[idnum] = Sink.JUSTIFY_CENTER;
1328 idnum++;
1329 }
1330
1331 Map<String, Integer> totalByRepo = new HashMap<String, Integer>();
1332 TotalCell totaldeps = new TotalCell( DEFAULT_DECIMAL_FORMAT );
1333
1334 startTable( justificationRepo, false );
1335
1336 tableHeader( tableHeader );
1337
1338 for ( Artifact dependency : alldeps )
1339 {
1340 totaldeps.incrementTotal( dependency.getScope() );
1341
1342 sink.tableRow();
1343
1344 tableCell( dependency.getId() );
1345
1346 if ( Artifact.SCOPE_SYSTEM.equals( dependency.getScope() ) )
1347 {
1348 for ( @SuppressWarnings( "unused" )
1349 String repoId : repoIdList )
1350 {
1351 tableCell( "-" );
1352 }
1353 }
1354 else
1355 {
1356 for ( String repokey : repoIdList )
1357 {
1358 ArtifactRepository repo = repoMap.get( repokey );
1359
1360 String depUrl = repoUtils.getDependencyUrlFromRepository( dependency, repo );
1361
1362 Integer old = totalByRepo.get( repokey );
1363 if ( old == null )
1364 {
1365 old = 0;
1366 totalByRepo.put( repokey, old );
1367 }
1368
1369 boolean dependencyExists = false;
1370
1371 if ( ( dependency.isSnapshot() && repo.getSnapshots().isEnabled() )
1372 || ( !dependency.isSnapshot() && repo.getReleases().isEnabled() ) )
1373 {
1374 dependencyExists = repoUtils.dependencyExistsInRepo( repo, dependency );
1375 }
1376
1377 if ( dependencyExists )
1378 {
1379 sink.tableCell();
1380 if ( StringUtils.isNotEmpty( depUrl ) )
1381 {
1382 sink.link( depUrl );
1383 }
1384 else
1385 {
1386 sink.text( depUrl );
1387 }
1388
1389 sink.figure();
1390 sink.figureCaption();
1391 sink.text( "Found at " + repo.getUrl() );
1392 sink.figureCaption_();
1393 sink.figureGraphics( "images/icon_success_sml.gif" );
1394 sink.figure_();
1395
1396 sink.link_();
1397 sink.tableCell_();
1398
1399 totalByRepo.put( repokey, old.intValue() + 1 );
1400 }
1401 else
1402 {
1403 tableCell( "-" );
1404 }
1405 }
1406 }
1407
1408 sink.tableRow_();
1409 }
1410
1411
1412
1413
1414 tableHeader[0] = getI18nString( "file.details.total" );
1415 tableHeader( tableHeader );
1416 String[] totalRow = new String[repoIdList.size() + 1];
1417 totalRow[0] = totaldeps.toString();
1418 idnum = 1;
1419 for ( String repokey : repoIdList )
1420 {
1421 Integer deps = totalByRepo.get( repokey );
1422 totalRow[idnum++] = deps != null ? deps.toString() : "0";
1423 }
1424
1425 tableRow( totalRow );
1426
1427 endTable();
1428 }
1429
1430
1431
1432
1433
1434 private boolean hasClassifier( List<Artifact> artifacts )
1435 {
1436 for ( Artifact artifact : artifacts )
1437 {
1438 if ( StringUtils.isNotEmpty( artifact.getClassifier() ) )
1439 {
1440 return true;
1441 }
1442 }
1443
1444 return false;
1445 }
1446
1447
1448
1449
1450
1451 private boolean hasOptional( List<Artifact> artifacts )
1452 {
1453 for ( Artifact artifact : artifacts )
1454 {
1455 if ( artifact.isOptional() )
1456 {
1457 return true;
1458 }
1459 }
1460
1461 return false;
1462 }
1463
1464
1465
1466
1467
1468 private boolean hasSealed( List<Artifact> artifacts )
1469 {
1470 for ( Artifact artifact : artifacts )
1471 {
1472
1473 if ( artifact.getFile() == null )
1474 {
1475 if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
1476 {
1477
1478 continue;
1479 }
1480
1481 try
1482 {
1483 repoUtils.resolve( artifact );
1484 }
1485 catch ( ArtifactResolutionException e )
1486 {
1487 log.error( "Artifact " + artifact.getId() + " can't be resolved.", e );
1488 continue;
1489 }
1490 catch ( ArtifactNotFoundException e )
1491 {
1492 if ( ( dependencies.getProject().getGroupId().equals( artifact.getGroupId() ) )
1493 && ( dependencies.getProject().getArtifactId().equals( artifact.getArtifactId() ) )
1494 && ( dependencies.getProject().getVersion().equals( artifact.getVersion() ) ) )
1495 {
1496 log.warn( "The artifact of this project has never been deployed." );
1497 }
1498 else
1499 {
1500 log.error( "Artifact " + artifact.getId() + " not found.", e );
1501 }
1502
1503 continue;
1504 }
1505
1506 if ( artifact.getFile() == null )
1507 {
1508 log.error( "Artifact " + artifact.getId() + " has no file, even after resolution." );
1509 continue;
1510 }
1511 }
1512
1513 if ( JAR_SUBTYPE.contains( artifact.getType().toLowerCase() ) )
1514 {
1515 try
1516 {
1517 JarData jarDetails = dependencies.getJarDependencyDetails( artifact );
1518 if ( jarDetails.isSealed() )
1519 {
1520 return true;
1521 }
1522 }
1523 catch ( IOException e )
1524 {
1525 log.error( "Artifact: " + artifact.getId() + " caused IOException: " + e.getMessage(), e );
1526 }
1527 }
1528 }
1529 return false;
1530 }
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543 static class FileDecimalFormat
1544 extends DecimalFormat
1545 {
1546 private static final long serialVersionUID = 4062503546523610081L;
1547
1548 private final I18N i18n;
1549
1550 private final Locale locale;
1551
1552
1553
1554
1555
1556
1557
1558 public FileDecimalFormat( I18N i18n, Locale locale )
1559 {
1560 super( "###0.00" );
1561
1562 this.i18n = i18n;
1563 this.locale = locale;
1564 }
1565
1566
1567 public StringBuffer format( long fs, StringBuffer result, FieldPosition fieldPosition )
1568 {
1569 if ( fs > 1000 * 1000 * 1000 )
1570 {
1571 result = super.format( (float) fs / ( 1000 * 1000 * 1000 ), result, fieldPosition );
1572 result.append( " " ).append( getString( "report.dependencies.file.details.column.size.gb" ) );
1573 return result;
1574 }
1575
1576 if ( fs > 1000 * 1000 )
1577 {
1578 result = super.format( (float) fs / ( 1000 * 1000 ), result, fieldPosition );
1579 result.append( " " ).append( getString( "report.dependencies.file.details.column.size.mb" ) );
1580 return result;
1581 }
1582
1583 result = super.format( (float) fs / ( 1000 ), result, fieldPosition );
1584 result.append( " " ).append( getString( "report.dependencies.file.details.column.size.kb" ) );
1585 return result;
1586 }
1587
1588 private String getString( String key )
1589 {
1590 return i18n.getString( "project-info-report", locale, key );
1591 }
1592 }
1593
1594
1595
1596
1597 static class TotalCell
1598 {
1599 static final int SCOPES_COUNT = 5;
1600
1601 final DecimalFormat decimalFormat;
1602
1603 long total = 0;
1604
1605 long totalCompileScope = 0;
1606
1607 long totalTestScope = 0;
1608
1609 long totalRuntimeScope = 0;
1610
1611 long totalProvidedScope = 0;
1612
1613 long totalSystemScope = 0;
1614
1615 TotalCell( DecimalFormat decimalFormat )
1616 {
1617 this.decimalFormat = decimalFormat;
1618 }
1619
1620 void incrementTotal( String scope )
1621 {
1622 addTotal( 1, scope );
1623 }
1624
1625 static String getScope( int index )
1626 {
1627 switch ( index )
1628 {
1629 case 0:
1630 return Artifact.SCOPE_COMPILE;
1631 case 1:
1632 return Artifact.SCOPE_TEST;
1633 case 2:
1634 return Artifact.SCOPE_RUNTIME;
1635 case 3:
1636 return Artifact.SCOPE_PROVIDED;
1637 case 4:
1638 return Artifact.SCOPE_SYSTEM;
1639 default:
1640 return null;
1641 }
1642 }
1643
1644 long getTotal( int index )
1645 {
1646 switch ( index )
1647 {
1648 case 0:
1649 return totalCompileScope;
1650 case 1:
1651 return totalTestScope;
1652 case 2:
1653 return totalRuntimeScope;
1654 case 3:
1655 return totalProvidedScope;
1656 case 4:
1657 return totalSystemScope;
1658 default:
1659 return total;
1660 }
1661 }
1662
1663 String getTotalString( int index )
1664 {
1665 long totalString = getTotal( index );
1666
1667 if ( totalString <= 0 )
1668 {
1669 return "";
1670 }
1671
1672 StringBuilder sb = new StringBuilder();
1673 if ( index >= 0 )
1674 {
1675 sb.append( getScope( index ) ).append( ": " );
1676 }
1677 sb.append( decimalFormat.format( getTotal( index ) ) );
1678 return sb.toString();
1679 }
1680
1681 void addTotal( long add, String scope )
1682 {
1683 total += add;
1684
1685 if ( Artifact.SCOPE_COMPILE.equals( scope ) )
1686 {
1687 totalCompileScope += add;
1688 }
1689 else if ( Artifact.SCOPE_TEST.equals( scope ) )
1690 {
1691 totalTestScope += add;
1692 }
1693 else if ( Artifact.SCOPE_RUNTIME.equals( scope ) )
1694 {
1695 totalRuntimeScope += add;
1696 }
1697 else if ( Artifact.SCOPE_PROVIDED.equals( scope ) )
1698 {
1699 totalProvidedScope += add;
1700 }
1701 else if ( Artifact.SCOPE_SYSTEM.equals( scope ) )
1702 {
1703 totalSystemScope += add;
1704 }
1705 }
1706
1707
1708 public String toString()
1709 {
1710 StringBuilder sb = new StringBuilder();
1711 sb.append( decimalFormat.format( total ) );
1712 sb.append( " (" );
1713
1714 boolean needSeparator = false;
1715 for ( int i = 0; i < SCOPES_COUNT; i++ )
1716 {
1717 if ( getTotal( i ) > 0 )
1718 {
1719 if ( needSeparator )
1720 {
1721 sb.append( ", " );
1722 }
1723 sb.append( getTotalString( i ) );
1724 needSeparator = true;
1725 }
1726 }
1727
1728 sb.append( ")" );
1729
1730 return sb.toString();
1731 }
1732 }
1733 }