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