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