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