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.plugin.plugin.report;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.Locale;
24  import java.util.Map;
25  import java.util.Optional;
26  
27  import org.apache.commons.lang3.StringUtils;
28  import org.apache.maven.doxia.markup.Markup;
29  import org.apache.maven.doxia.sink.Sink;
30  import org.apache.maven.model.Plugin;
31  import org.apache.maven.model.Prerequisites;
32  import org.apache.maven.plugin.descriptor.MojoDescriptor;
33  import org.apache.maven.plugin.descriptor.PluginDescriptor;
34  import org.apache.maven.project.MavenProject;
35  import org.apache.maven.tools.plugin.ExtendedPluginDescriptor;
36  import org.apache.maven.tools.plugin.util.PluginUtils;
37  import org.codehaus.plexus.i18n.I18N;
38  import org.codehaus.plexus.util.xml.Xpp3Dom;
39  
40  /**
41   * Generates an overview page with the list of goals
42   * and a link to the goal's page.
43   */
44  class PluginOverviewRenderer extends AbstractPluginReportRenderer {
45  
46      private final List<RequirementsHistory> requirementsHistories;
47  
48      private final PluginDescriptor pluginDescriptor;
49  
50      private final boolean hasExtensionsToLoad;
51  
52      /**
53       * @param sink                  not null
54       * @param i18n                  not null
55       * @param locale                not null
56       * @param project               not null
57       * @param requirementsHistories not null
58       * @param pluginDescriptor      not null
59       */
60      PluginOverviewRenderer(
61              Sink sink,
62              I18N i18n,
63              Locale locale,
64              MavenProject project,
65              List<RequirementsHistory> requirementsHistories,
66              PluginDescriptor pluginDescriptor,
67              boolean hasExtensionsToLoad) {
68          super(sink, locale, i18n, project);
69  
70          this.requirementsHistories = requirementsHistories;
71  
72          this.pluginDescriptor = pluginDescriptor;
73  
74          this.hasExtensionsToLoad = hasExtensionsToLoad;
75      }
76  
77      /**
78       * {@inheritDoc}
79       */
80      @Override
81      protected void renderBody() {
82          startSection(getTitle());
83  
84          if (!(pluginDescriptor.getMojos() != null && pluginDescriptor.getMojos().size() > 0)) {
85              paragraph(getI18nString("goals.nogoal"));
86              endSection();
87              return;
88          }
89  
90          paragraph(getI18nString("goals.intro"));
91  
92          boolean hasMavenReport = false;
93          for (MojoDescriptor mojo : pluginDescriptor.getMojos()) {
94              if (PluginUtils.isMavenReport(mojo.getImplementation(), project)) {
95                  hasMavenReport = true;
96              }
97          }
98  
99          startTable();
100 
101         String goalColumnName = getI18nString("goals.column.goal");
102         String isMavenReport = getI18nString("goals.column.isMavenReport");
103         String descriptionColumnName = getI18nString("goals.column.description");
104         if (hasMavenReport) {
105             tableHeader(new String[] {goalColumnName, isMavenReport, descriptionColumnName});
106         } else {
107             tableHeader(new String[] {goalColumnName, descriptionColumnName});
108         }
109 
110         List<MojoDescriptor> mojos = new ArrayList<>();
111         mojos.addAll(pluginDescriptor.getMojos());
112         PluginUtils.sortMojos(mojos);
113         for (MojoDescriptor mojo : mojos) {
114             sink.tableRow();
115 
116             String goalName = mojo.getFullGoalName();
117             /*
118              * Added ./ to define a relative path
119              * @see AbstractMavenReportRenderer#getValidHref(java.lang.String)
120              */
121             String goalDocumentationLink = "./" + mojo.getGoal() + "-mojo.html";
122             sink.tableCell();
123             link(goalDocumentationLink, goalName);
124             sink.tableCell_();
125 
126             if (hasMavenReport) {
127                 if (PluginUtils.isMavenReport(mojo.getImplementation(), project)) {
128                     tableCell(getI18nString("isReport"));
129                 } else {
130                     tableCell(getI18nString("isNotReport"));
131                 }
132             }
133 
134             String description;
135             if (StringUtils.isNotEmpty(mojo.getDeprecated())) {
136                 description = "<strong>" + getI18nString("goal.deprecated") + "</strong> " + mojo.getDeprecated();
137             } else if (StringUtils.isNotEmpty(mojo.getDescription())) {
138                 description = mojo.getDescription();
139             } else {
140                 description = getI18nString("goal.nodescription");
141             }
142             tableCell(description, true);
143             sink.tableRow_();
144         }
145 
146         endTable();
147 
148         startSection(getI18nString("systemrequirements"));
149 
150         paragraph(getI18nString("systemrequirements.intro"));
151 
152         startTable();
153 
154         String maven = discoverMavenRequirement(project, pluginDescriptor);
155         sink.tableRow();
156         tableCell(getI18nString("systemrequirements.maven"));
157         tableCell((maven != null ? maven : getI18nString("systemrequirements.nominimum")));
158         sink.tableRow_();
159 
160         String jdk = discoverJdkRequirement(project, pluginDescriptor);
161         sink.tableRow();
162         tableCell(getI18nString("systemrequirements.jdk"));
163         tableCell((jdk != null ? jdk : getI18nString("systemrequirements.nominimum")));
164         sink.tableRow_();
165 
166         endTable();
167 
168         endSection();
169 
170         renderRequirementsHistories();
171 
172         renderUsageSection(hasMavenReport);
173 
174         endSection();
175     }
176 
177     private void renderRequirementsHistories() {
178         if (requirementsHistories.isEmpty()) {
179             return;
180         }
181 
182         startSection(getI18nString("systemrequirements.history"));
183         paragraph(getI18nString("systemrequirements.history.intro"));
184 
185         startTable();
186         tableHeader(new String[] {
187             getI18nString("systemrequirements.history.version"),
188             getI18nString("systemrequirements.history.maven"),
189             getI18nString("systemrequirements.history.jdk")
190         });
191 
192         requirementsHistories.forEach(requirementsHistory -> {
193             sink.tableRow();
194             tableCell(requirementsHistory.getVersion());
195             tableCell(requirementsHistory.getMaven());
196             tableCell(requirementsHistory.getJdk());
197             sink.tableRow_();
198         });
199         endTable();
200 
201         endSection();
202     }
203 
204     /**
205      * Render the section about the usage of the plugin.
206      *
207      * @param hasMavenReport If the plugin has a report or not
208      */
209     private void renderUsageSection(boolean hasMavenReport) {
210         startSection(getI18nString("usage"));
211 
212         // Configuration
213         paragraph(getI18nString("usage.intro"));
214 
215         StringBuilder sb = new StringBuilder();
216         sb.append("<project>").append(Markup.EOL);
217         sb.append("  ...").append(Markup.EOL);
218         sb.append("  <build>").append(Markup.EOL);
219         sb.append("    <!-- " + getI18nString("usage.pluginManagement") + " -->")
220                 .append(Markup.EOL);
221         sb.append("    <pluginManagement>").append(Markup.EOL);
222         sb.append("      <plugins>").append(Markup.EOL);
223         sb.append("        <plugin>").append(Markup.EOL);
224         sb.append("          <groupId>")
225                 .append(pluginDescriptor.getGroupId())
226                 .append("</groupId>")
227                 .append(Markup.EOL);
228         sb.append("          <artifactId>")
229                 .append(pluginDescriptor.getArtifactId())
230                 .append("</artifactId>")
231                 .append(Markup.EOL);
232         sb.append("          <version>")
233                 .append(pluginDescriptor.getVersion())
234                 .append("</version>")
235                 .append(Markup.EOL);
236         if (hasExtensionsToLoad) {
237             sb.append("          <extensions>true</extensions>").append(Markup.EOL);
238         }
239         sb.append("        </plugin>").append(Markup.EOL);
240         sb.append("        ...").append(Markup.EOL);
241         sb.append("      </plugins>").append(Markup.EOL);
242         sb.append("    </pluginManagement>").append(Markup.EOL);
243         sb.append("    <!-- " + getI18nString("usage.plugins") + " -->").append(Markup.EOL);
244         sb.append("    <plugins>").append(Markup.EOL);
245         sb.append("      <plugin>").append(Markup.EOL);
246         sb.append("        <groupId>")
247                 .append(pluginDescriptor.getGroupId())
248                 .append("</groupId>")
249                 .append(Markup.EOL);
250         sb.append("        <artifactId>")
251                 .append(pluginDescriptor.getArtifactId())
252                 .append("</artifactId>")
253                 .append(Markup.EOL);
254         sb.append("      </plugin>").append(Markup.EOL);
255         sb.append("      ...").append(Markup.EOL);
256         sb.append("    </plugins>").append(Markup.EOL);
257         sb.append("  </build>").append(Markup.EOL);
258 
259         if (hasMavenReport) {
260             sb.append("  ...").append(Markup.EOL);
261             sb.append("  <!-- " + getI18nString("usage.reporting") + " -->").append(Markup.EOL);
262             sb.append("  <reporting>").append(Markup.EOL);
263             sb.append("    <plugins>").append(Markup.EOL);
264             sb.append("      <plugin>").append(Markup.EOL);
265             sb.append("        <groupId>")
266                     .append(pluginDescriptor.getGroupId())
267                     .append("</groupId>")
268                     .append(Markup.EOL);
269             sb.append("        <artifactId>")
270                     .append(pluginDescriptor.getArtifactId())
271                     .append("</artifactId>")
272                     .append(Markup.EOL);
273             sb.append("        <version>")
274                     .append(pluginDescriptor.getVersion())
275                     .append("</version>")
276                     .append(Markup.EOL);
277             sb.append("      </plugin>").append(Markup.EOL);
278             sb.append("      ...").append(Markup.EOL);
279             sb.append("    </plugins>").append(Markup.EOL);
280             sb.append("  </reporting>").append(Markup.EOL);
281         }
282 
283         sb.append("  ...").append(Markup.EOL);
284         sb.append("</project>");
285 
286         verbatimText(sb.toString());
287 
288         sink.paragraph();
289         linkPatternedText(getI18nString("configuration.end"));
290         sink.paragraph_();
291 
292         endSection();
293     }
294 
295     /**
296      * Tries to determine the Maven requirement from either the plugin descriptor or (if not set) from the
297      * Maven prerequisites element in the POM.
298      *
299      * @param project      not null
300      * @param pluginDescriptor the plugin descriptor (not null)
301      * @return the Maven version or null if not specified
302      */
303     private static String discoverMavenRequirement(MavenProject project, PluginDescriptor pluginDescriptor) {
304         if (StringUtils.isNotBlank(pluginDescriptor.getRequiredMavenVersion())) {
305             return pluginDescriptor.getRequiredMavenVersion();
306         }
307         return Optional.ofNullable(project.getPrerequisites())
308                 .map(Prerequisites::getMaven)
309                 .orElse(null);
310     }
311 
312     /**
313      * Tries to determine the JDK requirement from the following sources (until one is found)
314      * <ol>
315      * <li>use JDK requirement from plugin descriptor</li>
316      * <li>use {@code release} configuration of {@code org.apache.maven.plugins:maven-compiler-plugin}</li>
317      * <li>use {@code maven.compiler.release<} property</li>
318      * <li>use {@code target} configuration of {@code org.apache.maven.plugins:maven-compiler-plugin}</li>
319      * <li>use {@code maven.compiler.target} property</li>
320      * </ol>
321      *
322      * @param project      not null
323      * @param pluginDescriptor the plugin descriptor (not null)
324      * @return the JDK version
325      */
326     private static String discoverJdkRequirement(MavenProject project, PluginDescriptor pluginDescriptor) {
327         String jdk = null;
328         if (pluginDescriptor instanceof ExtendedPluginDescriptor) {
329             ExtendedPluginDescriptor extPluginDescriptor = (ExtendedPluginDescriptor) pluginDescriptor;
330             jdk = extPluginDescriptor.getRequiredJavaVersion();
331         }
332         if (jdk != null) {
333             return jdk;
334         }
335         Plugin compiler = getCompilerPlugin(project.getBuild().getPluginsAsMap());
336         if (compiler == null) {
337             compiler = getCompilerPlugin(project.getPluginManagement().getPluginsAsMap());
338         }
339 
340         jdk = getPluginParameter(compiler, "release");
341         if (jdk != null) {
342             return jdk;
343         }
344 
345         jdk = project.getProperties().getProperty("maven.compiler.release");
346         if (jdk != null) {
347             return jdk;
348         }
349 
350         jdk = getPluginParameter(compiler, "target");
351         if (jdk != null) {
352             return jdk;
353         }
354 
355         // default value
356         jdk = project.getProperties().getProperty("maven.compiler.target");
357         if (jdk != null) {
358             return jdk;
359         }
360 
361         String version = (compiler == null) ? null : compiler.getVersion();
362 
363         if (version != null) {
364             return "Default target for maven-compiler-plugin version " + version;
365         }
366 
367         return null;
368     }
369 
370     private static Plugin getCompilerPlugin(Map<String, Plugin> pluginsAsMap) {
371         return pluginsAsMap.get("org.apache.maven.plugins:maven-compiler-plugin");
372     }
373 
374     private static String getPluginParameter(Plugin plugin, String parameter) {
375         if (plugin != null) {
376             Xpp3Dom pluginConf = (Xpp3Dom) plugin.getConfiguration();
377 
378             if (pluginConf != null) {
379                 Xpp3Dom target = pluginConf.getChild(parameter);
380 
381                 if (target != null) {
382                     return target.getValue();
383                 }
384             }
385         }
386 
387         return null;
388     }
389 
390     @Override
391     protected String getI18nSection() {
392         return "plugin";
393     }
394 }