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