View Javadoc
1   package org.apache.maven.plugins.javadoc;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.nio.file.Path;
24  import java.util.Collection;
25  import java.util.Locale;
26  import java.util.Map;
27  import java.util.ResourceBundle;
28  import java.util.stream.Collectors;
29  
30  import org.apache.maven.doxia.sink.Sink;
31  import org.apache.maven.doxia.siterenderer.RenderingContext;
32  import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
33  import org.apache.maven.plugin.MojoExecutionException;
34  import org.apache.maven.plugin.MojoFailureException;
35  import org.apache.maven.plugins.annotations.Execute;
36  import org.apache.maven.plugins.annotations.LifecyclePhase;
37  import org.apache.maven.plugins.annotations.Mojo;
38  import org.apache.maven.plugins.annotations.Parameter;
39  import org.apache.maven.plugins.annotations.ResolutionScope;
40  import org.apache.maven.reporting.MavenReport;
41  import org.apache.maven.reporting.MavenReportException;
42  import org.codehaus.plexus.util.StringUtils;
43  
44  /**
45   * Generates documentation for the <code>Java code</code> in an <b>NON aggregator</b> project using the standard
46   * <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/javadoc/">Javadoc Tool</a>.
47   *
48   * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
49   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
50   * @since 2.0
51   * @see <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/javadoc/">Javadoc Tool</a>
52   * @see <a href="http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#options">Javadoc Options</a>
53   */
54  @Mojo( name = "javadoc", requiresDependencyResolution = ResolutionScope.COMPILE, threadSafe = true )
55  @Execute( phase = LifecyclePhase.GENERATE_SOURCES )
56  public class JavadocReport
57      extends AbstractJavadocMojo
58      implements MavenReport
59  {
60      // ----------------------------------------------------------------------
61      // Report Mojo Parameters
62      // ----------------------------------------------------------------------
63  
64      /**
65       * Specifies the destination directory where javadoc saves the generated HTML files.
66       */
67      @Parameter( property = "reportOutputDirectory", defaultValue = "${project.reporting.outputDirectory}/apidocs",
68                  required = true )
69      private File reportOutputDirectory;
70  
71      /**
72       * The name of the destination directory.
73       * <br/>
74       *
75       * @since 2.1
76       */
77      @Parameter( property = "destDir", defaultValue = "apidocs" )
78      private String destDir;
79  
80      /**
81       * The name 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 = "name" )
87      private String name;
88  
89      /**
90       * The description of the Javadoc report to be displayed in the Maven Generated Reports page
91       * (i.e. <code>project-reports.html</code>).
92       *
93       * @since 2.1
94       */
95      @Parameter( property = "description" )
96      private String description;
97  
98      // ----------------------------------------------------------------------
99      // Report public methods
100     // ----------------------------------------------------------------------
101 
102     /** {@inheritDoc} */
103     @Override
104     public String getName( Locale locale )
105     {
106         if ( StringUtils.isEmpty( name ) )
107         {
108             return getBundle( locale ).getString( "report.javadoc.name" );
109         }
110 
111         return name;
112     }
113 
114     /** {@inheritDoc} */
115     @Override
116     public String getDescription( Locale locale )
117     {
118         if ( StringUtils.isEmpty( description ) )
119         {
120             return getBundle( locale ).getString( "report.javadoc.description" );
121         }
122 
123         return description;
124     }
125 
126     public void generate( org.codehaus.doxia.sink.Sink sink, Locale locale )
127         throws MavenReportException
128     {
129         generate( (Sink) sink, locale );
130     }
131 
132     /** {@inheritDoc} */
133     @Override
134     public void generate( Sink sink, Locale locale )
135         throws MavenReportException
136     {
137         outputDirectory = getReportOutputDirectory();
138 
139         try
140         {
141             executeReport( locale );
142         }
143         catch ( MavenReportException | RuntimeException e )
144         {
145             if ( failOnError )
146             {
147                 throw e;
148             }
149             getLog().error( "Error while creating javadoc report: " + e.getMessage(), e );
150         }
151     }
152 
153     /** {@inheritDoc} */
154     @Override
155     public String getOutputName()
156     {
157         return destDir + "/index";
158     }
159 
160     /** {@inheritDoc} */
161     @Override
162     public boolean isExternalReport()
163     {
164         return true;
165     }
166 
167     /**
168      * {@inheritDoc}
169      *
170      * <br>
171      * The logic is the following:
172      * <table><caption>Can-generate-report Matrix</caption>
173      *   <tbody>
174      *     <tr>
175      *       <th> isAggregator </th>
176      *       <th> hasSourceFiles </th>
177      *       <th> isRootProject </th>
178      *       <th> Generate Report </th>
179      *     </tr>
180      *     <tr>
181      *       <td>True</td>
182      *       <td>True</td>
183      *       <td>True</td>
184      *       <td>True</td>
185      *     </tr>
186      *     <tr>
187      *       <td>True</td>
188      *       <td>True</td>
189      *       <td>False</td>
190      *       <td>False</td>
191      *     </tr>
192      *     <tr>
193      *       <td>True</td>
194      *       <td>False</td>
195      *       <td>True</td>
196      *       <td>False</td>
197      *     </tr>
198      *     <tr>
199      *       <td>True</td>
200      *       <td>False</td>
201      *       <td>False</td>
202      *       <td>False</td>
203      *     </tr>
204      *     <tr>
205      *       <td>False</td>
206      *       <td>True</td>
207      *       <td>True</td>
208      *       <td>True</td>
209      *     </tr>
210      *     <tr>
211      *       <td>False</td>
212      *       <td>True</td>
213      *       <td>False</td>
214      *       <td>True</td>
215      *     </tr>
216      *     <tr>
217      *        <td>False</td>
218      *        <td>False</td>
219      *        <td>True</td>
220      *        <td>False</td>
221      *      </tr>
222      *      <tr>
223      *        <td>False</td>
224      *        <td>False</td>
225      *        <td>False</td>
226      *        <td>False</td>
227      *      </tr>
228      *    </tbody>
229      *  </table>
230      */
231     @Override
232     public boolean canGenerateReport()
233     {
234         boolean canGenerate = false;
235 
236         if ( this.isAggregator() || !"pom".equals( this.project.getPackaging() ) )
237         {
238             Collection<Path> sourcePaths;
239             Map<Path, Collection<String>> files;
240             try
241             {
242                 sourcePaths = getSourcePaths().stream()
243                                 .flatMap( e -> e.getSourcePaths().stream() )
244                                 .collect( Collectors.toList() );
245                 files = getFiles( sourcePaths );
246             }
247             catch ( MavenReportException e )
248             {
249                 getLog().error( e.getMessage(), e );
250                 return false;
251             }
252 
253             canGenerate = canGenerateReport( files );
254         }
255         if ( getLog().isDebugEnabled() )
256         {
257             getLog().debug( " canGenerateReport = " + canGenerate + " for project " + this.project );
258         }
259         return canGenerate;
260     }
261 
262     /** {@inheritDoc} */
263     @Override
264     public String getCategoryName()
265     {
266         return CATEGORY_PROJECT_REPORTS;
267     }
268 
269     /** {@inheritDoc} */
270     @Override
271     public File getReportOutputDirectory()
272     {
273         if ( reportOutputDirectory == null )
274         {
275             return outputDirectory;
276         }
277 
278         return reportOutputDirectory;
279     }
280 
281     /**
282      * Method to set the directory where the generated reports will be put
283      *
284      * @param reportOutputDirectory the directory file to be set
285      */
286     @Override
287     public void setReportOutputDirectory( File reportOutputDirectory )
288     {
289         updateReportOutputDirectory( reportOutputDirectory, destDir );
290     }
291 
292     /**
293      * @param theDestDir The destination directory.
294      */
295     public void setDestDir( String theDestDir )
296     {
297         this.destDir = theDestDir;
298         updateReportOutputDirectory( reportOutputDirectory, theDestDir );
299     }
300 
301     private void updateReportOutputDirectory( File reportOutputDirectory, String destDir )
302     {
303         if ( reportOutputDirectory != null && destDir != null
304              && !reportOutputDirectory.getAbsolutePath().endsWith( destDir ) )
305         {
306             this.reportOutputDirectory = new File( reportOutputDirectory, destDir );
307         }
308         else
309         {
310             this.reportOutputDirectory = reportOutputDirectory;
311         }
312     }
313 
314     /** {@inheritDoc} */
315     @Override
316     public void doExecute()
317         throws MojoExecutionException, MojoFailureException
318     {
319         if ( skip )
320         {
321             getLog().info( "Skipping javadoc generation" );
322             return;
323         }
324 
325         try
326         {
327             RenderingContext context = new RenderingContext( outputDirectory, getOutputName() + ".html" );
328             SiteRendererSink sink = new SiteRendererSink( context );
329             Locale locale = Locale.getDefault();
330             generate( sink, locale );
331         }
332         catch ( MavenReportException | RuntimeException e )
333         {
334             failOnError( "An error has occurred in " + getName( Locale.ENGLISH ) + " report generation", e );
335         }
336     }
337 
338     /**
339      * Gets the resource bundle for the specified locale.
340      *
341      * @param locale The locale of the currently generated report.
342      * @return The resource bundle for the requested locale.
343      */
344     private ResourceBundle getBundle( Locale locale )
345     {
346         return ResourceBundle.getBundle( "javadoc-report", locale, getClass().getClassLoader() );
347     }
348 }