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 javax.inject.Inject;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.net.MalformedURLException;
26  import java.util.List;
27  import java.util.Locale;
28  
29  import org.apache.maven.artifact.repository.ArtifactRepository;
30  import org.apache.maven.doxia.sink.Sink;
31  import org.apache.maven.doxia.tools.SiteTool;
32  import org.apache.maven.model.DistributionManagement;
33  import org.apache.maven.model.Site;
34  import org.apache.maven.plugin.logging.Log;
35  import org.apache.maven.plugins.annotations.Mojo;
36  import org.apache.maven.project.DefaultProjectBuildingRequest;
37  import org.apache.maven.project.MavenProject;
38  import org.apache.maven.project.ProjectBuilder;
39  import org.apache.maven.project.ProjectBuildingException;
40  import org.apache.maven.project.ProjectBuildingRequest;
41  import org.apache.maven.reporting.MavenReportException;
42  import org.apache.maven.repository.RepositorySystem;
43  import org.codehaus.plexus.i18n.I18N;
44  
45  /**
46   * Generates the Project Modules report.
47   *
48   * @author ltheussl
49   * @since 2.2
50   */
51  @Mojo(name = "modules")
52  public class ModulesReport extends AbstractProjectInfoReport {
53  
54      @Inject
55      public ModulesReport(RepositorySystem repositorySystem, I18N i18n, ProjectBuilder projectBuilder) {
56          super(repositorySystem, i18n, projectBuilder);
57      }
58  
59      // ----------------------------------------------------------------------
60      // Public methods
61      // ----------------------------------------------------------------------
62  
63      @Override
64      public boolean canGenerateReport() throws MavenReportException {
65          boolean result = super.canGenerateReport();
66          if (result && skipEmptyReport) {
67              result = !isEmpty(getProject().getModel().getModules());
68          }
69  
70          return result;
71      }
72  
73      @Override
74      public void executeReport(Locale locale) {
75          new ModulesRenderer(
76                          getSink(),
77                          getProject(),
78                          getReactorProjects(),
79                          projectBuilder,
80                          getSession().getProjectBuildingRequest(),
81                          getSession().getLocalRepository(),
82                          getI18N(locale),
83                          locale,
84                          getLog(),
85                          siteTool)
86                  .render();
87      }
88  
89      /** {@inheritDoc} */
90      public String getOutputName() {
91          return "modules";
92      }
93  
94      @Override
95      protected String getI18Nsection() {
96          return "modules";
97      }
98  
99      // ----------------------------------------------------------------------
100     // Private
101     // ----------------------------------------------------------------------
102 
103     /**
104      * Internal renderer class
105      */
106     static class ModulesRenderer extends AbstractProjectInfoRenderer {
107 
108         protected final Log log;
109 
110         protected MavenProject project;
111 
112         protected List<MavenProject> reactorProjects;
113 
114         protected ProjectBuilder projectBuilder;
115 
116         protected ProjectBuildingRequest buildingRequest;
117 
118         protected ArtifactRepository localRepository;
119 
120         protected SiteTool siteTool;
121 
122         ModulesRenderer(
123                 Sink sink,
124                 MavenProject project,
125                 List<MavenProject> reactorProjects,
126                 ProjectBuilder projectBuilder,
127                 ProjectBuildingRequest buildingRequest,
128                 ArtifactRepository localRepository,
129                 I18N i18n,
130                 Locale locale,
131                 Log log,
132                 SiteTool siteTool) {
133             super(sink, i18n, locale);
134 
135             this.project = project;
136             this.reactorProjects = reactorProjects;
137             this.projectBuilder = projectBuilder;
138             this.buildingRequest = buildingRequest;
139             this.localRepository = localRepository;
140             this.siteTool = siteTool;
141             this.log = log;
142         }
143 
144         @Override
145         protected String getI18Nsection() {
146             return "modules";
147         }
148 
149         @Override
150         protected void renderBody() {
151             List<String> modules = project.getModel().getModules();
152 
153             if (modules == null || modules.isEmpty()) {
154                 startSection(getTitle());
155 
156                 paragraph(getI18nString("nolist"));
157 
158                 endSection();
159 
160                 return;
161             }
162 
163             startSection(getTitle());
164 
165             paragraph(getI18nString("intro"));
166 
167             startTable();
168 
169             String name = getI18nString("header.name");
170             String description = getI18nString("header.description");
171             tableHeader(new String[] {name, description});
172 
173             final String baseUrl = getDistMgmntSiteUrl(project);
174 
175             ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest(this.buildingRequest);
176             buildingRequest.setLocalRepository(localRepository);
177             buildingRequest.setProcessPlugins(false);
178 
179             for (String module : modules) {
180                 MavenProject moduleProject = getModuleFromReactor(project, reactorProjects, module);
181 
182                 if (moduleProject == null) {
183                     log.warn("Module " + module + " not found in reactor: loading locally");
184 
185                     File f = new File(project.getBasedir(), module + "/pom.xml");
186                     if (f.exists()) {
187                         try {
188                             moduleProject =
189                                     projectBuilder.build(f, buildingRequest).getProject();
190                         } catch (ProjectBuildingException e) {
191                             throw new IllegalStateException("Unable to read local module POM", e);
192                         }
193                     } else {
194                         moduleProject = new MavenProject();
195                         moduleProject.setName(module);
196                         moduleProject.setDistributionManagement(new DistributionManagement());
197                         moduleProject.getDistributionManagement().setSite(new Site());
198                         moduleProject.getDistributionManagement().getSite().setUrl(module);
199                     }
200                 }
201                 final String moduleName =
202                         (moduleProject.getName() == null) ? moduleProject.getArtifactId() : moduleProject.getName();
203                 final String moduleHref =
204                         getRelativeLink(baseUrl, getDistMgmntSiteUrl(moduleProject), moduleProject.getArtifactId());
205 
206                 tableRow(new String[] {linkedName(moduleName, moduleHref), moduleProject.getDescription()});
207             }
208 
209             endTable();
210 
211             endSection();
212         }
213 
214         private MavenProject getModuleFromReactor(
215                 MavenProject project, List<MavenProject> reactorProjects, String module) {
216             // Mainly case of unit test
217             if (reactorProjects == null) {
218                 return null;
219             }
220             try {
221                 File moduleBasedir = new File(project.getBasedir(), module).getCanonicalFile();
222 
223                 for (MavenProject reactorProject : reactorProjects) {
224                     if (moduleBasedir.equals(reactorProject.getBasedir())) {
225                         return reactorProject;
226                     }
227                 }
228             } catch (IOException e) {
229                 log.error("Error while populating modules menu: " + e.getMessage(), e);
230             }
231             // module not found in reactor
232             return null;
233         }
234 
235         /**
236          * Return distributionManagement.site.url if defined, null otherwise.
237          *
238          * @param project not null
239          * @return could be null
240          */
241         private static String getDistMgmntSiteUrl(MavenProject project) {
242             return getDistMgmntSiteUrl(project.getDistributionManagement());
243         }
244 
245         private static String getDistMgmntSiteUrl(DistributionManagement distMgmnt) {
246             if (distMgmnt != null
247                     && distMgmnt.getSite() != null
248                     && distMgmnt.getSite().getUrl() != null) {
249                 return urlEncode(distMgmnt.getSite().getUrl());
250             }
251 
252             return null;
253         }
254 
255         private static String urlEncode(final String url) {
256             if (url == null) {
257                 return null;
258             }
259 
260             try {
261                 return new File(url).toURI().toURL().toExternalForm();
262             } catch (MalformedURLException ex) {
263                 return url; // this will then throw somewhere else
264             }
265         }
266 
267         // adapted from DefaultSiteTool#appendMenuItem
268         private String getRelativeLink(String baseUrl, String href, String defaultHref) {
269             String selectedHref = href;
270 
271             if (selectedHref == null) {
272                 selectedHref = defaultHref;
273             }
274 
275             if (baseUrl != null) {
276                 selectedHref = siteTool.getRelativePath(selectedHref, baseUrl);
277             }
278 
279             if (selectedHref.endsWith("/")) {
280                 selectedHref = selectedHref.concat("index.html");
281             } else {
282                 selectedHref = selectedHref.concat("/index.html");
283             }
284 
285             return selectedHref;
286         }
287 
288         private String linkedName(String name, String link) {
289             return "{" + name + ", ./" + link + "}";
290         }
291     }
292 }