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     /** {@inheritDoc} */
127     @Override
128     public void generate( Sink sink, Locale locale )
129         throws MavenReportException
130     {
131         outputDirectory = getReportOutputDirectory();
132 
133         try
134         {
135             executeReport( locale );
136         }
137         catch ( MavenReportException | RuntimeException e )
138         {
139             if ( failOnError )
140             {
141                 throw e;
142             }
143             getLog().error( "Error while creating javadoc report: " + e.getMessage(), e );
144         }
145     }
146 
147     /** {@inheritDoc} */
148     @Override
149     public String getOutputName()
150     {
151         return destDir + "/index";
152     }
153 
154     /** {@inheritDoc} */
155     @Override
156     public boolean isExternalReport()
157     {
158         return true;
159     }
160 
161     /**
162      * {@inheritDoc}
163      *
164      * <br>
165      * The logic is the following:
166      * <table><caption>Can-generate-report Matrix</caption>
167      *   <tbody>
168      *     <tr>
169      *       <th> isAggregator </th>
170      *       <th> hasSourceFiles </th>
171      *       <th> isRootProject </th>
172      *       <th> Generate Report </th>
173      *     </tr>
174      *     <tr>
175      *       <td>True</td>
176      *       <td>True</td>
177      *       <td>True</td>
178      *       <td>True</td>
179      *     </tr>
180      *     <tr>
181      *       <td>True</td>
182      *       <td>True</td>
183      *       <td>False</td>
184      *       <td>False</td>
185      *     </tr>
186      *     <tr>
187      *       <td>True</td>
188      *       <td>False</td>
189      *       <td>True</td>
190      *       <td>False</td>
191      *     </tr>
192      *     <tr>
193      *       <td>True</td>
194      *       <td>False</td>
195      *       <td>False</td>
196      *       <td>False</td>
197      *     </tr>
198      *     <tr>
199      *       <td>False</td>
200      *       <td>True</td>
201      *       <td>True</td>
202      *       <td>True</td>
203      *     </tr>
204      *     <tr>
205      *       <td>False</td>
206      *       <td>True</td>
207      *       <td>False</td>
208      *       <td>True</td>
209      *     </tr>
210      *     <tr>
211      *        <td>False</td>
212      *        <td>False</td>
213      *        <td>True</td>
214      *        <td>False</td>
215      *      </tr>
216      *      <tr>
217      *        <td>False</td>
218      *        <td>False</td>
219      *        <td>False</td>
220      *        <td>False</td>
221      *      </tr>
222      *    </tbody>
223      *  </table>
224      */
225     @Override
226     public boolean canGenerateReport()
227     {
228         boolean canGenerate = false;
229 
230         if ( this.isAggregator() || !"pom".equals( this.project.getPackaging() ) )
231         {
232             Collection<Path> sourcePaths;
233             Map<Path, Collection<String>> files;
234             try
235             {
236                 sourcePaths = getSourcePaths().stream()
237                                 .flatMap( e -> e.getSourcePaths().stream() )
238                                 .collect( Collectors.toList() );
239                 files = getFiles( sourcePaths );
240             }
241             catch ( MavenReportException e )
242             {
243                 getLog().error( e.getMessage(), e );
244                 return false;
245             }
246 
247             canGenerate = canGenerateReport( files );
248         }
249         if ( getLog().isDebugEnabled() )
250         {
251             getLog().debug( " canGenerateReport = " + canGenerate + " for project " + this.project );
252         }
253         return canGenerate;
254     }
255 
256     /** {@inheritDoc} */
257     @Override
258     public String getCategoryName()
259     {
260         return CATEGORY_PROJECT_REPORTS;
261     }
262 
263     /** {@inheritDoc} */
264     @Override
265     public File getReportOutputDirectory()
266     {
267         if ( reportOutputDirectory == null )
268         {
269             return outputDirectory;
270         }
271 
272         return reportOutputDirectory;
273     }
274 
275     /**
276      * Method to set the directory where the generated reports will be put
277      *
278      * @param reportOutputDirectory the directory file to be set
279      */
280     @Override
281     public void setReportOutputDirectory( File reportOutputDirectory )
282     {
283         updateReportOutputDirectory( reportOutputDirectory, destDir );
284     }
285 
286     /**
287      * @param theDestDir The destination directory.
288      */
289     public void setDestDir( String theDestDir )
290     {
291         this.destDir = theDestDir;
292         updateReportOutputDirectory( reportOutputDirectory, theDestDir );
293     }
294 
295     private void updateReportOutputDirectory( File reportOutputDirectory, String destDir )
296     {
297         if ( reportOutputDirectory != null && destDir != null
298              && !reportOutputDirectory.getAbsolutePath().endsWith( destDir ) )
299         {
300             this.reportOutputDirectory = new File( reportOutputDirectory, destDir );
301         }
302         else
303         {
304             this.reportOutputDirectory = reportOutputDirectory;
305         }
306     }
307 
308     /** {@inheritDoc} */
309     @Override
310     public void doExecute()
311         throws MojoExecutionException, MojoFailureException
312     {
313         if ( skip )
314         {
315             getLog().info( "Skipping javadoc generation" );
316             return;
317         }
318 
319         try
320         {
321             RenderingContext context = new RenderingContext( outputDirectory, getOutputName() + ".html" );
322             SiteRendererSink sink = new SiteRendererSink( context );
323             Locale locale = Locale.getDefault();
324             generate( sink, locale );
325         }
326         catch ( MavenReportException | RuntimeException e )
327         {
328             failOnError( "An error has occurred in " + getName( Locale.ENGLISH ) + " report generation", e );
329         }
330     }
331 
332     /**
333      * Gets the resource bundle for the specified locale.
334      *
335      * @param locale The locale of the currently generated report.
336      * @return The resource bundle for the requested locale.
337      */
338     private ResourceBundle getBundle( Locale locale )
339     {
340         return ResourceBundle.getBundle( "javadoc-report", locale, getClass().getClassLoader() );
341     }
342 }