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