View Javadoc

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.util.Collections;
23  import java.util.Comparator;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Locale;
27  import java.util.Map;
28  
29  import org.apache.maven.artifact.Artifact;
30  import org.apache.maven.artifact.factory.ArtifactFactory;
31  import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
32  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
33  import org.apache.maven.artifact.repository.ArtifactRepository;
34  import org.apache.maven.artifact.versioning.ArtifactVersion;
35  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
36  import org.apache.maven.artifact.versioning.VersionRange;
37  import org.apache.maven.doxia.sink.Sink;
38  import org.apache.maven.model.Dependency;
39  import org.apache.maven.model.License;
40  import org.apache.maven.plugin.logging.Log;
41  import org.apache.maven.project.MavenProject;
42  import org.apache.maven.project.MavenProjectBuilder;
43  import org.apache.maven.project.ProjectBuildingException;
44  import org.apache.maven.report.projectinfo.AbstractProjectInfoRenderer;
45  import org.apache.maven.report.projectinfo.ProjectInfoReportUtils;
46  import org.apache.maven.report.projectinfo.dependencies.ManagementDependencies;
47  import org.apache.maven.report.projectinfo.dependencies.RepositoryUtils;
48  import org.codehaus.plexus.i18n.I18N;
49  import org.codehaus.plexus.util.StringUtils;
50  
51  /**
52   * @author Nick Stolwijk
53   * @version $Id: DependencyManagementRenderer.java 1397965 2012-10-13 22:51:30Z hboutemy $
54   * @since 2.1
55   */
56  public class DependencyManagementRenderer
57      extends AbstractProjectInfoRenderer
58  {
59      private final ManagementDependencies dependencies;
60  
61      private final Log log;
62  
63      private final ArtifactMetadataSource artifactMetadataSource;
64  
65      private final ArtifactFactory artifactFactory;
66  
67      private final MavenProjectBuilder mavenProjectBuilder;
68  
69      private final List<ArtifactRepository> remoteRepositories;
70  
71      private final ArtifactRepository localRepository;
72  
73      private final RepositoryUtils repoUtils;
74  
75      /**
76       * Default constructor
77       *
78       * @param sink
79       * @param locale
80       * @param i18n
81       * @param log
82       * @param artifactFactory
83       * @param dependencies
84       * @param mavenProjectBuilder
85       * @param remoteRepositories
86       * @param localRepository
87       * @param repoUtils
88       */
89      public DependencyManagementRenderer( Sink sink, Locale locale, I18N i18n, Log log,
90                                           ManagementDependencies dependencies,
91                                           ArtifactMetadataSource artifactMetadataSource,
92                                           ArtifactFactory artifactFactory, MavenProjectBuilder mavenProjectBuilder,
93                                           List<ArtifactRepository> remoteRepositories,
94                                           ArtifactRepository localRepository, RepositoryUtils repoUtils )
95      {
96          super( sink, i18n, locale );
97  
98          this.log = log;
99          this.dependencies = dependencies;
100         this.artifactMetadataSource = artifactMetadataSource;
101         this.artifactFactory = artifactFactory;
102         this.mavenProjectBuilder = mavenProjectBuilder;
103         this.remoteRepositories = remoteRepositories;
104         this.localRepository = localRepository;
105         this.repoUtils = repoUtils;
106     }
107 
108     // ----------------------------------------------------------------------
109     // Public methods
110     // ----------------------------------------------------------------------
111 
112     @Override
113     protected String getI18Nsection()
114     {
115         return "dependencyManagement";
116     }
117 
118     @Override
119     public void renderBody()
120     {
121         // Dependencies report
122 
123         if ( !dependencies.hasDependencies() )
124         {
125             startSection( getTitle() );
126 
127             paragraph( getI18nString( "nolist" ) );
128 
129             endSection();
130 
131             return;
132         }
133 
134         // === Section: Project Dependencies.
135         renderSectionProjectDependencies();
136     }
137 
138     // ----------------------------------------------------------------------
139     // Private methods
140     // ----------------------------------------------------------------------
141 
142     private void renderSectionProjectDependencies()
143     {
144         startSection( getTitle() );
145 
146         // collect dependencies by scope
147         Map<String, List<Dependency>> dependenciesByScope = dependencies.getManagementDependenciesByScope();
148 
149         renderDependenciesForAllScopes( dependenciesByScope );
150 
151         endSection();
152     }
153 
154     private void renderDependenciesForAllScopes( Map<String, List<Dependency>> dependenciesByScope )
155     {
156         renderDependenciesForScope( Artifact.SCOPE_COMPILE, dependenciesByScope.get( Artifact.SCOPE_COMPILE ) );
157         renderDependenciesForScope( Artifact.SCOPE_RUNTIME, dependenciesByScope.get( Artifact.SCOPE_RUNTIME ) );
158         renderDependenciesForScope( Artifact.SCOPE_TEST, dependenciesByScope.get( Artifact.SCOPE_TEST ) );
159         renderDependenciesForScope( Artifact.SCOPE_PROVIDED, dependenciesByScope.get( Artifact.SCOPE_PROVIDED ) );
160         renderDependenciesForScope( Artifact.SCOPE_SYSTEM, dependenciesByScope.get( Artifact.SCOPE_SYSTEM ) );
161     }
162 
163     private String[] getDependencyTableHeader( boolean hasClassifier )
164     {
165         String groupId = getI18nString( "column.groupId" );
166         String artifactId = getI18nString( "column.artifactId" );
167         String version = getI18nString( "column.version" );
168         String classifier = getI18nString( "column.classifier" );
169         String type = getI18nString( "column.type" );
170         String license = getI18nString( "column.license" );
171 
172         if ( hasClassifier )
173         {
174             return new String[] { groupId, artifactId, version, classifier, type, license };
175         }
176 
177         return new String[] { groupId, artifactId, version, type, license };
178     }
179 
180     private void renderDependenciesForScope( String scope, List<Dependency> artifacts )
181     {
182         if ( artifacts != null )
183         {
184             // can't use straight artifact comparison because we want optional last
185             Collections.sort( artifacts, getDependencyComparator() );
186 
187             startSection( scope );
188 
189             paragraph( getI18nString( "intro." + scope ) );
190             startTable();
191 
192             boolean hasClassifier = false;
193             for ( Dependency dependency : artifacts )
194             {
195                 if ( StringUtils.isNotEmpty( dependency.getClassifier() ) )
196                 {
197                     hasClassifier = true;
198                     break;
199                 }
200             }
201 
202             String[] tableHeader = getDependencyTableHeader( hasClassifier );
203             tableHeader( tableHeader );
204 
205             for ( Dependency dependency : artifacts )
206             {
207                 tableRow( getDependencyRow( dependency, hasClassifier ) );
208             }
209             endTable();
210 
211             endSection();
212         }
213     }
214 
215     @SuppressWarnings( "unchecked" )
216     private String[] getDependencyRow( Dependency dependency, boolean hasClassifier )
217     {
218         Artifact artifact =
219             artifactFactory.createProjectArtifact( dependency.getGroupId(), dependency.getArtifactId(),
220                                                    dependency.getVersion() );
221 
222         StringBuilder licensesBuffer = new StringBuilder();
223         String url = null;
224         try
225         {
226             VersionRange range = VersionRange.createFromVersionSpec( dependency.getVersion() );
227 
228             if ( range.getRecommendedVersion() == null )
229             {
230                 // MPIR-216: no direct version but version range: need to choose one precise version
231                 log.debug( "Resolving range for DependencyManagement on " + artifact.getId() );
232 
233                 List<ArtifactVersion> versions =
234                     artifactMetadataSource.retrieveAvailableVersions( artifact, localRepository, remoteRepositories );
235     
236                 // only use versions from range
237                 for ( Iterator<ArtifactVersion> iter = versions.iterator(); iter.hasNext(); )
238                 {
239                     if ( ! range.containsVersion( iter.next() ) )
240                     {
241                         iter.remove();
242                     }
243                 }
244 
245                 // select latest, assuming pom information will be the most accurate
246                 if ( versions.size() > 0 )
247                 {
248                     Collections.sort( versions );
249                     
250                     artifact.setVersion( versions.get( versions.size() - 1 ).toString() );
251                     log.debug( "DependencyManagement resolved: " + artifact.getId() );
252                 }
253             }
254 
255             url =
256                 ProjectInfoReportUtils.getArtifactUrl( artifactFactory, artifact, mavenProjectBuilder,
257                                                        remoteRepositories, localRepository );
258 
259             MavenProject artifactProject = repoUtils.getMavenProjectFromRepository( artifact );
260 
261             List<License> licenses = artifactProject.getLicenses();
262             for ( License license : licenses )
263             {
264                 String licenseCell = ProjectInfoReportUtils.getArtifactIdCell( license.getName(), license.getUrl() );
265                 if ( licensesBuffer.length() > 0 )
266                 {
267                     licensesBuffer.append( ", " );
268                 }
269                 licensesBuffer.append( licenseCell );
270             }
271         }
272         catch ( InvalidVersionSpecificationException e )
273         {
274             log.warn( "Unable to parse version for " + artifact.getId(), e );
275         }
276         catch ( ArtifactMetadataRetrievalException e )
277         {
278             log.warn( "Unable to retrieve versions for " + artifact.getId() + " from repository.", e );
279         }
280         catch ( ProjectBuildingException e )
281         {
282             log.warn( "Unable to create Maven project for " + artifact.getId() + " from repository.", e );
283         }
284 
285         String artifactIdCell = ProjectInfoReportUtils.getArtifactIdCell( artifact.getArtifactId(), url );
286 
287         if ( hasClassifier )
288         {
289             return new String[] { dependency.getGroupId(), artifactIdCell, dependency.getVersion(),
290                 dependency.getClassifier(), dependency.getType(), licensesBuffer.toString() };
291         }
292 
293         return new String[] { dependency.getGroupId(), artifactIdCell, dependency.getVersion(),
294             dependency.getType(), licensesBuffer.toString() };
295     }
296 
297     private Comparator<Dependency> getDependencyComparator()
298     {
299         return new Comparator<Dependency>()
300         {
301             public int compare( Dependency a1, Dependency a2 )
302             {
303                 int result = a1.getGroupId().compareTo( a2.getGroupId() );
304                 if ( result != 0 )
305                 {
306                     return result;
307                 }
308 
309                 result = a1.getArtifactId().compareTo( a2.getArtifactId() );
310                 if ( result != 0 )
311                 {
312                     return result;
313                 }
314 
315                 result = a1.getType().compareTo( a2.getType() );
316                 if ( result != 0 )
317                 {
318                     return result;
319                 }
320 
321                 if ( a1.getClassifier() == null )
322                 {
323                     if ( a2.getClassifier() != null )
324                     {
325                         return 1;
326                     }
327                 }
328                 else
329                 {
330                     if ( a2.getClassifier() != null )
331                     {
332                         result = a1.getClassifier().compareTo( a2.getClassifier() );
333                     }
334                     else
335                     {
336                         return -1;
337                     }
338                 }
339 
340                 if ( result != 0 )
341                 {
342                     return result;
343                 }
344 
345                 // We don't consider the version range in the comparison, just the resolved version
346                 return a1.getVersion().compareTo( a2.getVersion() );
347             }
348         };
349     }
350 }