View Javadoc
1   package org.apache.maven.reporting;
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 org.apache.maven.doxia.sink.Sink;
23  import org.apache.maven.doxia.sink.SinkFactory;
24  import org.apache.maven.doxia.site.decoration.DecorationModel;
25  import org.apache.maven.doxia.siterenderer.Renderer;
26  import org.apache.maven.doxia.siterenderer.RendererException;
27  import org.apache.maven.doxia.siterenderer.RenderingContext;
28  import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
29  import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
30  import org.apache.maven.plugin.AbstractMojo;
31  import org.apache.maven.plugin.MojoExecutionException;
32  import org.apache.maven.plugins.annotations.Component;
33  import org.apache.maven.plugins.annotations.Parameter;
34  import org.apache.maven.project.MavenProject;
35  import org.apache.maven.shared.utils.WriterFactory;
36  import org.codehaus.plexus.util.ReaderFactory;
37  
38  import java.io.File;
39  import java.io.FileOutputStream;
40  import java.io.IOException;
41  import java.io.OutputStreamWriter;
42  import java.io.Writer;
43  import java.util.HashMap;
44  import java.util.Locale;
45  import java.util.Map;
46  
47  /**
48   * The basis for a Maven report which can be generated both as part of a site generation or
49   * as a direct standalone goal invocation.
50   * Both invocations are delegated to <code>abstract executeReport( Locale )</code> from:
51   * <ul>
52   * <li>Mojo's <code>execute()</code> method, see maven-plugin-api</li>
53   * <li>MavenMultiPageReport's <code>generate( Sink, SinkFactory, Locale )</code>, see maven-reporting-api</li>
54   * </ul>
55   *
56   * @author <a href="evenisse@apache.org">Emmanuel Venisse</a>
57   * @since 2.0
58   * @see #execute() <code>Mojo.execute()</code>, from maven-plugin-api
59   * @see #generate(Sink, SinkFactory, Locale) <code>MavenMultiPageReport.generate( Sink, SinkFactory, Locale )</code>,
60   *  from maven-reporting-api
61   * @see #executeReport(Locale) <code>abstract executeReport( Locale )</code>
62   */
63  public abstract class AbstractMavenReport
64      extends AbstractMojo
65      implements MavenMultiPageReport
66  {
67      /**
68       * The output directory for the report. Note that this parameter is only evaluated if the goal is run directly from
69       * the command line. If the goal is run indirectly as part of a site generation, the output directory configured in
70       * the Maven Site Plugin is used instead.
71       */
72      @Parameter( defaultValue = "${project.reporting.outputDirectory}", readonly = true, required = true )
73      protected File outputDirectory;
74  
75      /**
76       * The Maven Project.
77       */
78      @Parameter( defaultValue = "${project}", readonly = true, required = true )
79      protected MavenProject project;
80  
81      /**
82       * Specifies the input encoding.
83       */
84      @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}", readonly = true )
85      private String inputEncoding;
86  
87      /**
88       * Specifies the output encoding.
89       */
90      @Parameter( property = "outputEncoding", defaultValue = "${project.reporting.outputEncoding}", readonly = true )
91      private String outputEncoding;
92  
93      /**
94       * Doxia Site Renderer component.
95       */
96      @Component
97      protected Renderer siteRenderer;
98  
99      /** The current sink to use */
100     private Sink sink;
101 
102     /** The sink factory to use */
103     private SinkFactory sinkFactory;
104 
105     /** The current report output directory to use */
106     private File reportOutputDirectory;
107 
108     /**
109      * This method is called when the report generation is invoked directly as a standalone Mojo.
110      *
111      * @throws MojoExecutionException if an error occurs when generating the report
112      * @see org.apache.maven.plugin.Mojo#execute()
113      */
114     @Override
115     public void execute()
116         throws MojoExecutionException
117     {
118         if ( !canGenerateReport() )
119         {
120             return;
121         }
122 
123         File outputDirectory = new File( getOutputDirectory() );
124 
125         String filename = getOutputName() + ".html";
126 
127         Locale locale = Locale.getDefault();
128 
129         SiteRenderingContext siteContext = new SiteRenderingContext();
130         siteContext.setDecoration( new DecorationModel() );
131         siteContext.setTemplateName( "org/apache/maven/doxia/siterenderer/resources/default-site.vm" );
132         siteContext.setLocale( locale );
133         siteContext.setTemplateProperties( getTemplateProperties() );
134 
135         // TODO Replace null with real value
136         RenderingContext context = new RenderingContext( outputDirectory, filename, null );
137 
138         SiteRendererSink sink = new SiteRendererSink( context );
139 
140         try
141         {
142 
143             generate( sink, null, locale );
144 
145             if ( !isExternalReport() ) // MSHARED-204: only render Doxia sink if not an external report
146             {
147                 outputDirectory.mkdirs();
148 
149                 try ( Writer writer =
150                     new OutputStreamWriter( new FileOutputStream( new File( outputDirectory, filename ) ),
151                                             getOutputEncoding() ) )
152                 {
153                     getSiteRenderer().mergeDocumentIntoSite( writer, sink, siteContext );
154                 }
155             }
156         }
157         catch ( RendererException | IOException | MavenReportException e )
158         {
159             throw new MojoExecutionException(
160                 "An error has occurred in " + getName( Locale.ENGLISH ) + " report generation.", e );
161         }
162     }
163 
164     /**
165      * create template properties like done in maven-site-plugin's
166      * <code>AbstractSiteRenderingMojo.createSiteRenderingContext( Locale )</code>
167      * @return properties
168      */
169     private Map<String, Object> getTemplateProperties()
170     {
171         Map<String, Object> templateProperties = new HashMap<>();
172         templateProperties.put( "project", getProject() );
173         templateProperties.put( "inputEncoding", getInputEncoding() );
174         templateProperties.put( "outputEncoding", getOutputEncoding() );
175         // Put any of the properties in directly into the Velocity context
176         for ( Map.Entry<Object, Object> entry : getProject().getProperties().entrySet() )
177         {
178             templateProperties.put( (String) entry.getKey(), entry.getValue() );
179         }
180         return templateProperties;
181     }
182 
183     /**
184      * Generate a report.
185      *
186      * @param sink
187      * @param locale
188      * @throws MavenReportException
189      * @deprecated use {@link #generate(Sink, SinkFactory, Locale)} instead.
190      */
191     @Deprecated
192     @Override
193     public void generate( Sink sink, Locale locale )
194         throws MavenReportException
195     {
196         generate( sink, null, locale );
197     }
198 
199     /**
200      * This method is called when the report generation is invoked by maven-site-plugin.
201      *
202      * @param sink
203      * @param sinkFactory
204      * @param locale
205      * @throws MavenReportException
206      */
207     @Override
208     public void generate( Sink sink, SinkFactory sinkFactory, Locale locale )
209         throws MavenReportException
210     {
211         if ( !canGenerateReport() )
212         {
213             getLog().info( "This report cannot be generated as part of the current build. "
214                            + "The report name should be referenced in this line of output." );
215             return;
216         }
217 
218         this.sink = sink;
219 
220         this.sinkFactory = sinkFactory;
221 
222         executeReport( locale );
223 
224         closeReport();
225     }
226 
227     /**
228      * @return CATEGORY_PROJECT_REPORTS
229      */
230     @Override
231     public String getCategoryName()
232     {
233         return CATEGORY_PROJECT_REPORTS;
234     }
235 
236     @Override
237     public File getReportOutputDirectory()
238     {
239         if ( reportOutputDirectory == null )
240         {
241             reportOutputDirectory = new File( getOutputDirectory() );
242         }
243 
244         return reportOutputDirectory;
245     }
246 
247     @Override
248     public void setReportOutputDirectory( File reportOutputDirectory )
249     {
250         this.reportOutputDirectory = reportOutputDirectory;
251         this.outputDirectory = reportOutputDirectory;
252     }
253 
254     protected String getOutputDirectory()
255     {
256         return outputDirectory.getAbsolutePath();
257     }
258 
259     protected MavenProject getProject()
260     {
261         return project;
262     }
263 
264     protected Renderer getSiteRenderer()
265     {
266         return siteRenderer;
267     }
268 
269     /**
270      * Gets the input files encoding.
271      *
272      * @return The input files encoding, never <code>null</code>.
273      */
274     protected String getInputEncoding()
275     {
276         return ( inputEncoding == null ) ? ReaderFactory.FILE_ENCODING : inputEncoding;
277     }
278 
279     /**
280      * Gets the effective reporting output files encoding.
281      *
282      * @return The effective reporting output file encoding, never <code>null</code>.
283      */
284     protected String getOutputEncoding()
285     {
286         return ( outputEncoding == null ) ? WriterFactory.UTF_8 : outputEncoding;
287     }
288 
289     /**
290      * Actions when closing the report.
291      */
292     protected void closeReport()
293     {
294         getSink().close();
295     }
296 
297     /**
298      * @return the sink used
299      */
300     public Sink getSink()
301     {
302         return sink;
303     }
304 
305     /**
306      * @return the sink factory used
307      */
308     public SinkFactory getSinkFactory()
309     {
310         return sinkFactory;
311     }
312 
313     /**
314      * @see org.apache.maven.reporting.MavenReport#isExternalReport()
315      * @return {@code false} by default.
316      */
317     @Override
318     public boolean isExternalReport()
319     {
320         return false;
321     }
322 
323     @Override
324     public boolean canGenerateReport()
325     {
326         return true;
327     }
328 
329     /**
330      * Execute the generation of the report.
331      *
332      * @param locale the wanted locale to return the report's description, could be <code>null</code>.
333      * @throws MavenReportException if any
334      */
335     protected abstract void executeReport( Locale locale )
336         throws MavenReportException;
337 }