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