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