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.reporting.MavenReportException;
46  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
47  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
48  import org.apache.maven.shared.dependency.graph.DependencyNode;
49  import org.apache.maven.shared.jar.classes.JarClassesAnalysis;
50  import org.codehaus.plexus.util.IOUtil;
51  import org.codehaus.plexus.util.ReaderFactory;
52  
53  /**
54   * Generates the Project Dependencies report.
55   *
56   * @author <a href="mailto:jason@maven.org">Jason van Zyl </a>
57   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton </a>
58   * @since 2.0
59   */
60  @Mojo(name = "dependencies", requiresDependencyResolution = ResolutionScope.TEST)
61  public class DependenciesReport extends AbstractProjectInfoReport {
62      /**
63       * Images resources dir
64       */
65      private static final String RESOURCES_DIR = "org/apache/maven/report/projectinfo/resources";
66  
67      // ----------------------------------------------------------------------
68      // Mojo components
69      // ----------------------------------------------------------------------
70  
71      /**
72       * Dependency graph builder component.
73       *
74       * @since 2.5
75       */
76      @Component(hint = "default")
77      private DependencyGraphBuilder dependencyGraphBuilder;
78  
79      /**
80       * Jar classes analyzer component.
81       *
82       * @since 2.1
83       */
84      @Component
85      private JarClassesAnalysis classesAnalyzer;
86  
87      /**
88       * Repository metadata component.
89       *
90       * @since 2.1
91       */
92      @Component
93      private RepositoryMetadataManager repositoryMetadataManager;
94  
95      // ----------------------------------------------------------------------
96      // Mojo parameters
97      // ----------------------------------------------------------------------
98  
99      /**
100      * Display file details for each dependency, such as: file size, number of
101      * classes, number of packages etc.
102      *
103      * @since 2.1
104      */
105     @Parameter(property = "dependency.details.enabled", defaultValue = "true")
106     private boolean dependencyDetailsEnabled;
107 
108     // ----------------------------------------------------------------------
109     // Public methods
110     // ----------------------------------------------------------------------
111 
112     @Override
113     public boolean canGenerateReport() throws MavenReportException {
114         boolean result = super.canGenerateReport();
115         if (result && skipEmptyReport) {
116             // This seems to be a bit too much but the DependenciesRenderer applies the same logic
117             DependencyNode dependencyNode = resolveProject();
118             Dependencies dependencies = new Dependencies(project, dependencyNode, classesAnalyzer);
119             result = dependencies.hasDependencies();
120         }
121 
122         return result;
123     }
124 
125     @Override
126     public void executeReport(Locale locale) {
127         try {
128             copyResources(getReportOutputDirectory());
129         } catch (IOException e) {
130             getLog().error("Cannot copy resources", e);
131         }
132 
133         ProjectBuildingRequest buildingRequest =
134                 new DefaultProjectBuildingRequest(getSession().getProjectBuildingRequest());
135         buildingRequest.setLocalRepository(localRepository);
136         buildingRequest.setRemoteRepositories(remoteRepositories);
137         buildingRequest.setPluginArtifactRepositories(pluginRepositories);
138 
139         RepositoryUtils repoUtils = new RepositoryUtils(
140                 getLog(),
141                 projectBuilder,
142                 repositorySystem,
143                 resolver,
144                 remoteRepositories,
145                 pluginRepositories,
146                 buildingRequest,
147                 repositoryMetadataManager);
148 
149         DependencyNode dependencyNode = resolveProject();
150 
151         Dependencies dependencies = new Dependencies(project, dependencyNode, classesAnalyzer);
152 
153         DependenciesReportConfiguration config = new DependenciesReportConfiguration(dependencyDetailsEnabled);
154 
155         DependenciesRenderer r = new DependenciesRenderer(
156                 getSink(),
157                 locale,
158                 getI18N(locale),
159                 getLog(),
160                 dependencies,
161                 dependencyNode,
162                 config,
163                 repoUtils,
164                 repositorySystem,
165                 projectBuilder,
166                 buildingRequest,
167                 getLicenseMappings());
168         r.render();
169     }
170 
171     /**
172      * {@inheritDoc}
173      */
174     public String getOutputName() {
175         return "dependencies";
176     }
177 
178     @Override
179     protected String getI18Nsection() {
180         return "dependencies";
181     }
182 
183     // ----------------------------------------------------------------------
184     // Private methods
185     // ----------------------------------------------------------------------
186 
187     /**
188      * @return resolve the dependency tree
189      */
190     private DependencyNode resolveProject() {
191         try {
192             ArtifactFilter artifactFilter = new ScopeArtifactFilter(Artifact.SCOPE_TEST);
193             ProjectBuildingRequest buildingRequest =
194                     new DefaultProjectBuildingRequest(getSession().getProjectBuildingRequest());
195             buildingRequest.setProject(project);
196             return dependencyGraphBuilder.buildDependencyGraph(buildingRequest, artifactFilter);
197         } catch (DependencyGraphBuilderException e) {
198             getLog().error("Unable to build dependency tree.", e);
199             return null;
200         }
201     }
202 
203     /**
204      * @param outputDirectory the wanted output directory
205      * @throws IOException if any
206      */
207     private void copyResources(File outputDirectory) throws IOException {
208         InputStream resourceList = null;
209         InputStream in = null;
210         BufferedReader reader = null;
211         OutputStream out = null;
212         try {
213             resourceList = getClass().getClassLoader().getResourceAsStream(RESOURCES_DIR + "/resources.txt");
214 
215             if (resourceList != null) {
216                 reader = new LineNumberReader(new InputStreamReader(resourceList, ReaderFactory.US_ASCII));
217 
218                 for (String line = reader.readLine(); line != null; line = reader.readLine()) {
219                     in = getClass().getClassLoader().getResourceAsStream(RESOURCES_DIR + "/" + line);
220 
221                     if (in == null) {
222                         throw new IOException("The resource " + line + " doesn't exist.");
223                     }
224 
225                     File outputFile = new File(outputDirectory, line);
226 
227                     if (!outputFile.getParentFile().exists()) {
228                         outputFile.getParentFile().mkdirs();
229                     }
230 
231                     out = new FileOutputStream(outputFile);
232                     IOUtil.copy(in, out);
233                     out.close();
234                     out = null;
235                     in.close();
236                     in = null;
237                 }
238 
239                 reader.close();
240                 reader = null;
241             }
242         } finally {
243             IOUtil.close(out);
244             IOUtil.close(reader);
245             IOUtil.close(in);
246             IOUtil.close(resourceList);
247         }
248     }
249 }