View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.report.projectinfo;
20  
21  import java.io.BufferedReader;
22  import java.io.File;
23  import java.io.FileOutputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.InputStreamReader;
27  import java.io.LineNumberReader;
28  import java.io.OutputStream;
29  import java.util.Locale;
30  
31  import org.apache.maven.artifact.Artifact;
32  import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
33  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
34  import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
35  import org.apache.maven.plugins.annotations.Component;
36  import org.apache.maven.plugins.annotations.Mojo;
37  import org.apache.maven.plugins.annotations.Parameter;
38  import org.apache.maven.plugins.annotations.ResolutionScope;
39  import org.apache.maven.project.DefaultProjectBuildingRequest;
40  import org.apache.maven.project.ProjectBuildingRequest;
41  import org.apache.maven.report.projectinfo.dependencies.Dependencies;
42  import org.apache.maven.report.projectinfo.dependencies.DependenciesReportConfiguration;
43  import org.apache.maven.report.projectinfo.dependencies.RepositoryUtils;
44  import org.apache.maven.report.projectinfo.dependencies.renderer.DependenciesRenderer;
45  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
46  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
47  import org.apache.maven.shared.dependency.graph.DependencyNode;
48  import org.apache.maven.shared.jar.classes.JarClassesAnalysis;
49  import org.codehaus.plexus.util.IOUtil;
50  import org.codehaus.plexus.util.ReaderFactory;
51  
52  /**
53   * Generates the Project Dependencies report.
54   *
55   * @author <a href="mailto:jason@maven.org">Jason van Zyl </a>
56   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton </a>
57   * @since 2.0
58   */
59  @Mojo(name = "dependencies", requiresDependencyResolution = ResolutionScope.TEST)
60  public class DependenciesReport extends AbstractProjectInfoReport {
61      /**
62       * Images resources dir
63       */
64      private static final String RESOURCES_DIR = "org/apache/maven/report/projectinfo/resources";
65  
66      // ----------------------------------------------------------------------
67      // Mojo components
68      // ----------------------------------------------------------------------
69  
70      /**
71       * Dependency graph builder component.
72       *
73       * @since 2.5
74       */
75      @Component(hint = "default")
76      private DependencyGraphBuilder dependencyGraphBuilder;
77  
78      /**
79       * Jar classes analyzer component.
80       *
81       * @since 2.1
82       */
83      @Component
84      private JarClassesAnalysis classesAnalyzer;
85  
86      /**
87       * Repository metadata component.
88       *
89       * @since 2.1
90       */
91      @Component
92      private RepositoryMetadataManager repositoryMetadataManager;
93  
94      // ----------------------------------------------------------------------
95      // Mojo parameters
96      // ----------------------------------------------------------------------
97  
98      /**
99       * Display file details for each dependency, such as: file size, number of
100      * classes, number of packages etc.
101      *
102      * @since 2.1
103      */
104     @Parameter(property = "dependency.details.enabled", defaultValue = "true")
105     private boolean dependencyDetailsEnabled;
106 
107     // ----------------------------------------------------------------------
108     // Public methods
109     // ----------------------------------------------------------------------
110 
111     @Override
112     public boolean canGenerateReport() {
113         boolean result = super.canGenerateReport();
114         if (result && skipEmptyReport) {
115             // This seems to be a bit too much but the DependenciesRenderer applies the same logic
116             DependencyNode dependencyNode = resolveProject();
117             Dependencies dependencies = new Dependencies(project, dependencyNode, classesAnalyzer);
118             result = dependencies.hasDependencies();
119         }
120 
121         return result;
122     }
123 
124     @Override
125     public void executeReport(Locale locale) {
126         try {
127             copyResources(getReportOutputDirectory());
128         } catch (IOException e) {
129             getLog().error("Cannot copy resources", e);
130         }
131 
132         ProjectBuildingRequest buildingRequest =
133                 new DefaultProjectBuildingRequest(getSession().getProjectBuildingRequest());
134         buildingRequest.setLocalRepository(localRepository);
135         buildingRequest.setRemoteRepositories(remoteRepositories);
136         buildingRequest.setPluginArtifactRepositories(pluginRepositories);
137 
138         RepositoryUtils repoUtils = new RepositoryUtils(
139                 getLog(),
140                 projectBuilder,
141                 repositorySystem,
142                 resolver,
143                 remoteRepositories,
144                 pluginRepositories,
145                 buildingRequest,
146                 repositoryMetadataManager);
147 
148         DependencyNode dependencyNode = resolveProject();
149 
150         Dependencies dependencies = new Dependencies(project, dependencyNode, classesAnalyzer);
151 
152         DependenciesReportConfiguration config = new DependenciesReportConfiguration(dependencyDetailsEnabled);
153 
154         DependenciesRenderer r = new DependenciesRenderer(
155                 getSink(),
156                 locale,
157                 getI18N(locale),
158                 getLog(),
159                 dependencies,
160                 dependencyNode,
161                 config,
162                 repoUtils,
163                 repositorySystem,
164                 projectBuilder,
165                 buildingRequest,
166                 getLicenseMappings());
167         r.render();
168     }
169 
170     /**
171      * {@inheritDoc}
172      */
173     public String getOutputName() {
174         return "dependencies";
175     }
176 
177     @Override
178     protected String getI18Nsection() {
179         return "dependencies";
180     }
181 
182     // ----------------------------------------------------------------------
183     // Private methods
184     // ----------------------------------------------------------------------
185 
186     /**
187      * @return resolve the dependency tree
188      */
189     private DependencyNode resolveProject() {
190         try {
191             ArtifactFilter artifactFilter = new ScopeArtifactFilter(Artifact.SCOPE_TEST);
192             ProjectBuildingRequest buildingRequest =
193                     new DefaultProjectBuildingRequest(getSession().getProjectBuildingRequest());
194             buildingRequest.setProject(project);
195             return dependencyGraphBuilder.buildDependencyGraph(buildingRequest, artifactFilter);
196         } catch (DependencyGraphBuilderException e) {
197             getLog().error("Unable to build dependency tree.", e);
198             return null;
199         }
200     }
201 
202     /**
203      * @param outputDirectory the wanted output directory
204      * @throws IOException if any
205      */
206     private void copyResources(File outputDirectory) throws IOException {
207         InputStream resourceList = null;
208         InputStream in = null;
209         BufferedReader reader = null;
210         OutputStream out = null;
211         try {
212             resourceList = getClass().getClassLoader().getResourceAsStream(RESOURCES_DIR + "/resources.txt");
213 
214             if (resourceList != null) {
215                 reader = new LineNumberReader(new InputStreamReader(resourceList, ReaderFactory.US_ASCII));
216 
217                 for (String line = reader.readLine(); line != null; line = reader.readLine()) {
218                     in = getClass().getClassLoader().getResourceAsStream(RESOURCES_DIR + "/" + line);
219 
220                     if (in == null) {
221                         throw new IOException("The resource " + line + " doesn't exist.");
222                     }
223 
224                     File outputFile = new File(outputDirectory, line);
225 
226                     if (!outputFile.getParentFile().exists()) {
227                         outputFile.getParentFile().mkdirs();
228                     }
229 
230                     out = new FileOutputStream(outputFile);
231                     IOUtil.copy(in, out);
232                     out.close();
233                     out = null;
234                     in.close();
235                     in = null;
236                 }
237 
238                 reader.close();
239                 reader = null;
240             }
241         } finally {
242             IOUtil.close(out);
243             IOUtil.close(reader);
244             IOUtil.close(in);
245             IOUtil.close(resourceList);
246         }
247     }
248 }