View Javadoc
1   package org.apache.maven.plugins.site.render;
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.io.IOException;
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.List;
27  import java.util.Locale;
28  import java.util.Map;
29  import java.util.TreeMap;
30  
31  import org.apache.maven.doxia.siterenderer.DocumentRenderer;
32  import org.apache.maven.doxia.siterenderer.DoxiaDocumentRenderer;
33  import org.apache.maven.doxia.siterenderer.RendererException;
34  import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
35  import org.apache.maven.execution.MavenSession;
36  import org.apache.maven.plugin.MojoExecutionException;
37  import org.apache.maven.plugin.MojoFailureException;
38  import org.apache.maven.plugins.annotations.Mojo;
39  import org.apache.maven.plugins.annotations.Parameter;
40  import org.apache.maven.plugins.annotations.ResolutionScope;
41  import org.apache.maven.project.MavenProject;
42  import org.apache.maven.reporting.MavenReport;
43  import org.apache.maven.reporting.MavenReportException;
44  import org.apache.maven.reporting.exec.MavenReportExecution;
45  import org.apache.maven.shared.utils.logging.MessageBuilder;
46  
47  import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
48  
49  /**
50   * Generates the site for a single project.
51   * <p>
52   * Note that links between module sites in a multi module build will <b>not</b> work, since local build directory
53   * structure doesn't match deployed site.
54   * </p>
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   *
59   */
60  @Mojo( name = "site", requiresDependencyResolution = ResolutionScope.TEST, requiresReports = true )
61  public class SiteMojo
62      extends AbstractSiteRenderingMojo
63  {
64      /**
65       * Directory where the project sites and report distributions will be generated (as html/css/...).
66       */
67      @Parameter( property = "siteOutputDirectory", defaultValue = "${project.reporting.outputDirectory}" )
68      protected File outputDirectory;
69  
70      /**
71       * Convenience parameter that allows you to disable report generation.
72       */
73      @Parameter( property = "generateReports", defaultValue = "true" )
74      private boolean generateReports;
75  
76      /**
77       * Generate a sitemap. The result will be a "sitemap.html" file at the site root.
78       *
79       * @since 2.1
80       */
81      @Parameter( property = "generateSitemap", defaultValue = "false" )
82      private boolean generateSitemap;
83  
84      /**
85       * Whether to validate xml input documents. If set to true, <strong>all</strong> input documents in xml format (in
86       * particular xdoc and fml) will be validated and any error will lead to a build failure.
87       *
88       * @since 2.1.1
89       */
90      @Parameter( property = "validate", defaultValue = "false" )
91      private boolean validate;
92  
93      /**
94       * {@inheritDoc} Generate the project site
95       * <p/>
96       * throws MojoExecutionException if any
97       *
98       * @see org.apache.maven.plugin.Mojo#execute()
99       */
100     public void execute()
101         throws MojoExecutionException, MojoFailureException
102     {
103         if ( skip )
104         {
105             getLog().info( "maven.site.skip = true: Skipping site generation" );
106             return;
107         }
108 
109         if ( getLog().isDebugEnabled() )
110         {
111             getLog().debug( "executing Site Mojo" );
112         }
113 
114         checkInputEncoding();
115 
116         List<MavenReportExecution> reports;
117         if ( generateReports )
118         {
119             reports = getReports();
120         }
121         else
122         {
123             reports = Collections.emptyList();
124         }
125 
126         try
127         {
128             List<Locale> localesList = getLocales();
129 
130             // Default is first in the list
131             Locale defaultLocale = localesList.get( 0 );
132             Locale.setDefault( defaultLocale );
133 
134             for ( Locale locale : localesList )
135             {
136                 if ( locale == defaultLocale )
137                 {
138                     getLog().info( buffer().strong( "Rendering site with default locale " + locale.getDisplayName()
139                         + " (" + locale + ")" ).toString() );
140                 }
141                 else
142                 {
143                     getLog().info( "" );
144                     getLog().info( buffer().strong( "Rendering localized site for " + locale.getDisplayName() + " ("
145                         + locale + ")" ).toString() );
146                 }
147                 renderLocale( locale, reports );
148             }
149         }
150         catch ( RendererException e )
151         {
152             if ( e.getCause() instanceof MavenReportException )
153             {
154                 // issue caused by report, not really by Doxia Site Renderer
155                 throw new MojoExecutionException( e.getMessage(), e.getCause() );
156             }
157             throw new MojoExecutionException( e.getMessage(), e );
158         }
159         catch ( IOException e )
160         {
161             throw new MojoExecutionException( "Error during site generation", e );
162         }
163     }
164 
165     private void renderLocale( Locale locale, List<MavenReportExecution> reports )
166         throws IOException, RendererException, MojoFailureException, MojoExecutionException
167     {
168         SiteRenderingContext context = createSiteRenderingContext( locale );
169         // MSITE-723 add generated site directory, in case some content has been put in pre-site phase
170         context.addSiteDirectory( generatedSiteDirectory );
171 
172         context.setInputEncoding( getInputEncoding() );
173         context.setOutputEncoding( getOutputEncoding() );
174         context.setValidate( validate );
175         if ( validate )
176         {
177             getLog().info( "Validation is switched on, xml input documents will be validated!" );
178         }
179 
180         File outputDir = getOutputDirectory( locale );
181 
182         Map<String, DocumentRenderer> documents = locateDocuments( context, reports, locale );
183 
184         // copy resources
185         siteRenderer.copyResources( context, outputDir );
186 
187         // 1. render Doxia documents first
188         List<DocumentRenderer> reportDocuments = renderDoxiaDocuments( documents, context, outputDir, false );
189 
190         // 2. then reports
191         // prepare external reports
192         for ( MavenReportExecution mavenReportExecution : reports )
193         {
194             MavenReport report = mavenReportExecution.getMavenReport();
195             report.setReportOutputDirectory( outputDir );
196         }
197 
198         siteRenderer.render( reportDocuments, context, outputDir );
199 
200         if ( generateSitemap )
201         {
202             getLog().info( "Generating Sitemap." );
203 
204             new SiteMap( getOutputEncoding(), i18n ).generate( context.getDecoration(), generatedSiteDirectory,
205                                                                locale );
206         }
207 
208         // 3. Generated docs must be (re-)done afterwards as they are often generated by reports
209         context.getSiteDirectories().clear();
210         context.addSiteDirectory( generatedSiteDirectory );
211 
212         Map<String, DocumentRenderer> generatedDocuments =
213             siteRenderer.locateDocumentFiles( context, false /* not editable */ );
214 
215         renderDoxiaDocuments( generatedDocuments, context, outputDir, true );
216 
217         // copy generated resources also
218         siteRenderer.copyResources( context, outputDir );
219     }
220 
221     /**
222      * Render Doxia documents from the list given, but not reports.
223      * 
224      * @param documents a collection of documents containing both Doxia source files and reports
225      * @return the sublist of documents that are not Doxia source files
226      */
227     private List<DocumentRenderer> renderDoxiaDocuments( Map<String, DocumentRenderer> documents,
228                                                          SiteRenderingContext context, File outputDir,
229                                                          boolean generated )
230                                                              throws RendererException, IOException
231     {
232         Map<String, DocumentRenderer> doxiaDocuments = new TreeMap<>();
233         List<DocumentRenderer> nonDoxiaDocuments = new ArrayList<>();
234 
235         Map<String, Integer> counts = new TreeMap<>();
236 
237         for ( Map.Entry<String, DocumentRenderer> entry : documents.entrySet() )
238         {
239             DocumentRenderer doc = entry.getValue();
240 
241             if ( doc instanceof DoxiaDocumentRenderer )
242             {
243                 doxiaDocuments.put( entry.getKey(), doc );
244 
245                 DoxiaDocumentRenderer doxia = (DoxiaDocumentRenderer) doc;
246 
247                 // count documents per parserId
248                 String parserId = doxia.getRenderingContext().getParserId();
249                 Integer count = counts.get( parserId );
250                 if ( count == null )
251                 {
252                     count = 1;
253                 }
254                 else
255                 {
256                     count++;
257                 }
258                 counts.put( parserId, count );
259             }
260             else
261             {
262                 nonDoxiaDocuments.add( doc );
263             }
264         }
265 
266         if ( doxiaDocuments.size() > 0 )
267         {
268             MessageBuilder mb = buffer();
269             mb.a( "Rendering " );
270             mb.strong( doxiaDocuments.size() + ( generated ? " generated" : "" ) + " Doxia document"
271                 + ( doxiaDocuments.size() > 1 ? "s" : "" ) );
272             mb.a( ": " );
273 
274             boolean first = true;
275             for ( Map.Entry<String, Integer> entry : counts.entrySet() )
276             {
277                 if ( first )
278                 {
279                     first = false;
280                 }
281                 else
282                 {
283                     mb.a( ", " );
284                 }
285                 mb.strong( entry.getValue() + " " + entry.getKey() );
286             }
287 
288             getLog().info( mb.toString() );
289 
290             siteRenderer.render( doxiaDocuments.values(), context, outputDir );
291         }
292 
293         return nonDoxiaDocuments;
294     }
295 
296     private File getOutputDirectory( Locale locale )
297     {
298         File file;
299         if ( locale.getLanguage().equals( Locale.getDefault().getLanguage() ) )
300         {
301             file = outputDirectory;
302         }
303         else
304         {
305             file = new File( outputDirectory, locale.getLanguage() );
306         }
307 
308         // Safety
309         if ( !file.exists() )
310         {
311             file.mkdirs();
312         }
313 
314         return file;
315     }
316 
317     public MavenProject getProject()
318     {
319         return project;
320     }
321 
322     public MavenSession getSession()
323     {
324         return mavenSession;
325     }
326 }