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