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.plugins.javadoc;
20  
21  import javax.inject.Inject;
22  
23  import java.io.File;
24  import java.nio.file.Path;
25  import java.util.Collection;
26  import java.util.Locale;
27  import java.util.Map;
28  import java.util.ResourceBundle;
29  import java.util.stream.Collectors;
30  
31  import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
32  import org.apache.maven.doxia.sink.Sink;
33  import org.apache.maven.doxia.sink.SinkFactory;
34  import org.apache.maven.doxia.siterenderer.DocumentRenderingContext;
35  import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
36  import org.apache.maven.doxia.tools.SiteTool;
37  import org.apache.maven.plugin.MojoExecutionException;
38  import org.apache.maven.plugin.MojoFailureException;
39  import org.apache.maven.plugins.annotations.Execute;
40  import org.apache.maven.plugins.annotations.LifecyclePhase;
41  import org.apache.maven.plugins.annotations.Mojo;
42  import org.apache.maven.plugins.annotations.Parameter;
43  import org.apache.maven.plugins.annotations.ResolutionScope;
44  import org.apache.maven.plugins.javadoc.resolver.ResourceResolver;
45  import org.apache.maven.project.ProjectBuilder;
46  import org.apache.maven.reporting.MavenMultiPageReport;
47  import org.apache.maven.reporting.MavenReportException;
48  import org.apache.maven.toolchain.ToolchainManager;
49  import org.codehaus.plexus.archiver.manager.ArchiverManager;
50  import org.eclipse.aether.RepositorySystem;
51  
52  /**
53   * Generates documentation for the <code>Java code</code> in a <b>NON aggregator</b> project using the standard
54   * <a href="https://docs.oracle.com/en/java/javase/17/docs/specs/man/javadoc.html">Javadoc Tool</a>.
55   *
56   * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
57   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
58   * @since 2.0
59   * @see <a href="https://docs.oracle.com/en/java/javase/17/docs/specs/man/javadoc.html">Javadoc Tool</a>
60   */
61  @Mojo(name = "javadoc", requiresDependencyResolution = ResolutionScope.COMPILE, threadSafe = true)
62  @Execute(phase = LifecyclePhase.GENERATE_SOURCES)
63  public class JavadocReport extends AbstractJavadocMojo implements MavenMultiPageReport {
64      // ----------------------------------------------------------------------
65      // Report Mojo Parameters
66      // ----------------------------------------------------------------------
67  
68      /** The current shared report output directory to use */
69      private File reportOutputDirectory;
70  
71      /**
72       * The name of the Javadoc report to be displayed in the Maven Generated Reports page
73       * (i.e. <code>project-reports.html</code>).
74       *
75       * @since 2.1
76       */
77      @Parameter(property = "name")
78      private String name;
79  
80      /**
81       * The description of the Javadoc report to be displayed in the Maven Generated Reports page
82       * (i.e. <code>project-reports.html</code>).
83       *
84       * @since 2.1
85       */
86      @Parameter(property = "description")
87      private String description;
88  
89      @Inject
90      public JavadocReport(
91              SiteTool siteTool,
92              ArchiverManager archiverManager,
93              ResourceResolver resourceResolver,
94              RepositorySystem repoSystem,
95              ArtifactHandlerManager artifactHandlerManager,
96              ProjectBuilder mavenProjectBuilder,
97              ToolchainManager toolchainManager) {
98          super(
99                  siteTool,
100                 archiverManager,
101                 resourceResolver,
102                 repoSystem,
103                 artifactHandlerManager,
104                 mavenProjectBuilder,
105                 toolchainManager);
106     }
107 
108     // ----------------------------------------------------------------------
109     // Report public methods
110     // ----------------------------------------------------------------------
111 
112     /** {@inheritDoc} */
113     @Override
114     public String getName(Locale locale) {
115         if (name == null || name.isEmpty()) {
116             return getBundle(locale).getString("report.javadoc.name");
117         }
118 
119         return name;
120     }
121 
122     /** {@inheritDoc} */
123     @Override
124     public String getDescription(Locale locale) {
125         if (description == null || description.isEmpty()) {
126             return getBundle(locale).getString("report.javadoc.description");
127         }
128 
129         return description;
130     }
131 
132     /** {@inheritDoc} */
133     @Override
134     public void generate(Sink sink, Locale locale) throws MavenReportException {
135         generate(sink, null, locale);
136     }
137 
138     /** {@inheritDoc} */
139     @Override
140     public void generate(Sink sink, SinkFactory sinkFactory, Locale locale) throws MavenReportException {
141         try {
142             executeReport(locale);
143         } catch (MavenReportException | RuntimeException e) {
144             if (failOnError) {
145                 throw e;
146             }
147             getLog().error("Error while creating javadoc report: " + e.getMessage(), e);
148         }
149     }
150 
151     /**
152      * @deprecated use getOutputPath() instead
153      */
154     @Override
155     @Deprecated
156     public String getOutputName() {
157         return getOutputPath();
158     }
159 
160     /** {@inheritDoc} */
161     @Override
162     public String getOutputPath() {
163         return (isTest() ? "test" : "") + "apidocs" + "/index";
164     }
165 
166     /** {@inheritDoc} */
167     @Override
168     public boolean isExternalReport() {
169         return true;
170     }
171 
172     /**
173      * {@inheritDoc}
174      *
175      * <br>
176      * The logic is the following:
177      * <table><caption>Can-generate-report Matrix</caption>
178      *   <tbody>
179      *     <tr>
180      *       <th> isAggregator </th>
181      *       <th> hasSourceFiles </th>
182      *       <th> isRootProject </th>
183      *       <th> Generate Report </th>
184      *     </tr>
185      *     <tr>
186      *       <td>True</td>
187      *       <td>True</td>
188      *       <td>True</td>
189      *       <td>True</td>
190      *     </tr>
191      *     <tr>
192      *       <td>True</td>
193      *       <td>True</td>
194      *       <td>False</td>
195      *       <td>False</td>
196      *     </tr>
197      *     <tr>
198      *       <td>True</td>
199      *       <td>False</td>
200      *       <td>True</td>
201      *       <td>False</td>
202      *     </tr>
203      *     <tr>
204      *       <td>True</td>
205      *       <td>False</td>
206      *       <td>False</td>
207      *       <td>False</td>
208      *     </tr>
209      *     <tr>
210      *       <td>False</td>
211      *       <td>True</td>
212      *       <td>True</td>
213      *       <td>True</td>
214      *     </tr>
215      *     <tr>
216      *       <td>False</td>
217      *       <td>True</td>
218      *       <td>False</td>
219      *       <td>True</td>
220      *     </tr>
221      *     <tr>
222      *        <td>False</td>
223      *        <td>False</td>
224      *        <td>True</td>
225      *        <td>False</td>
226      *      </tr>
227      *      <tr>
228      *        <td>False</td>
229      *        <td>False</td>
230      *        <td>False</td>
231      *        <td>False</td>
232      *      </tr>
233      *    </tbody>
234      *  </table>
235      */
236     @Override
237     public boolean canGenerateReport() throws MavenReportException {
238         if (skip) {
239             return false;
240         }
241 
242         Collection<JavadocModule> sourcePaths = getSourcePaths();
243 
244         Collection<Path> collectedSourcePaths =
245                 sourcePaths.stream().flatMap(e -> e.getSourcePaths().stream()).collect(Collectors.toList());
246 
247         Map<Path, Collection<String>> files = getFiles(collectedSourcePaths);
248 
249         return canGenerateReport(files);
250     }
251 
252     /** {@inheritDoc} */
253     @Override
254     public String getCategoryName() {
255         return CATEGORY_PROJECT_REPORTS;
256     }
257 
258     /** {@inheritDoc} */
259     @Override
260     public File getReportOutputDirectory() {
261         if (reportOutputDirectory == null) {
262             reportOutputDirectory = new File(getOutputDirectory());
263         }
264 
265         return reportOutputDirectory;
266     }
267 
268     /** {@inheritDoc} */
269     @Override
270     public void setReportOutputDirectory(File reportOutputDirectory) {
271         this.reportOutputDirectory = reportOutputDirectory;
272         this.outputDirectory = reportOutputDirectory;
273     }
274 
275     /** {@inheritDoc} */
276     @Override
277     protected String getPluginReportOutputDirectory() {
278         return getReportOutputDirectory().getAbsolutePath() + "/" + (isTest() ? "test" : "") + "apidocs";
279     }
280 
281     /** {@inheritDoc} */
282     @Override
283     protected void doExecute() throws MojoExecutionException, MojoFailureException {
284         try {
285             if (!canGenerateReport()) {
286                 String reportMojoInfo = mojoExecution.getPlugin().getId() + ":" + mojoExecution.getGoal();
287                 getLog().info("Skipping " + reportMojoInfo + " report goal");
288                 return;
289             }
290         } catch (MavenReportException e) {
291             throw new MojoExecutionException("Failed to determine whether report can be generated", e);
292         }
293 
294         File outputDirectory = new File(getOutputDirectory());
295 
296         String filename = getOutputName() + ".html";
297 
298         Locale locale = SiteTool.DEFAULT_LOCALE;
299 
300         try {
301             String reportMojoInfo = mojoExecution.getPlugin().getId() + ":" + mojoExecution.getGoal();
302             DocumentRenderingContext docRenderingContext =
303                     new DocumentRenderingContext(outputDirectory, filename, reportMojoInfo);
304 
305             SiteRendererSink sink = new SiteRendererSink(docRenderingContext);
306 
307             generate(sink, null, locale);
308         } catch (MavenReportException | RuntimeException e) {
309             failOnError("An error has occurred in " + getName(Locale.ENGLISH) + " report generation", e);
310         }
311     }
312 
313     /**
314      * Gets the resource bundle for the specified locale.
315      *
316      * @param locale the locale of the currently generated report
317      * @return the resource bundle for the requested locale
318      */
319     private ResourceBundle getBundle(Locale locale) {
320         return ResourceBundle.getBundle("javadoc-report", locale, getClass().getClassLoader());
321     }
322 }