View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.site.render;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.Collections;
25  import java.util.List;
26  import java.util.Locale;
27  import java.util.Map;
28  import java.util.TreeMap;
29  
30  import org.apache.maven.doxia.siterenderer.DocumentRenderer;
31  import org.apache.maven.doxia.siterenderer.DoxiaDocumentRenderer;
32  import org.apache.maven.doxia.siterenderer.RendererException;
33  import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
34  import org.apache.maven.doxia.tools.SiteTool;
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 extends AbstractSiteRenderingMojo {
62      /**
63       * Directory where the project sites and report distributions will be generated (as html/css/...).
64       */
65      @Parameter(property = "siteOutputDirectory", defaultValue = "${project.reporting.outputDirectory}")
66      protected File outputDirectory;
67  
68      /**
69       * Convenience parameter that allows you to disable report generation.
70       */
71      @Parameter(property = "generateReports", defaultValue = "true")
72      private boolean generateReports;
73  
74      /**
75       * Generate a sitemap. The result will be a "sitemap.html" file at the site root.
76       *
77       * @since 2.1
78       */
79      @Parameter(property = "generateSitemap", defaultValue = "false")
80      private boolean generateSitemap;
81  
82      /**
83       * Whether to validate xml input documents. If set to true, <strong>all</strong> input documents in xml format (in
84       * particular xdoc and fml) will be validated and any error will lead to a build failure.
85       *
86       * @since 2.1.1
87       */
88      @Parameter(property = "validate", defaultValue = "false")
89      private boolean validate;
90  
91      /**
92       * {@inheritDoc}
93       */
94      public void execute() throws MojoExecutionException, MojoFailureException {
95          if (skip) {
96              getLog().info("maven.site.skip = true: Skipping site generation");
97              return;
98          }
99  
100         if (getLog().isDebugEnabled()) {
101             getLog().debug("executing Site Mojo");
102         }
103 
104         checkInputEncoding();
105 
106         List<MavenReportExecution> reports;
107         if (generateReports) {
108             reports = getReports();
109         } else {
110             reports = Collections.emptyList();
111         }
112 
113         try {
114             List<Locale> localesList = getLocales();
115 
116             // Default is first in the list
117             Locale defaultLocale = localesList.get(0);
118 
119             for (Locale locale : localesList) {
120                 getLog().info("Rendering site for "
121                         + buffer().strong((locale.equals(defaultLocale) ? "default locale" : "locale '" + locale + "'"))
122                                 .toString());
123                 renderLocale(locale, reports, localesList);
124             }
125         } catch (RendererException e) {
126             if (e.getCause() instanceof MavenReportException) {
127                 // issue caused by report, not really by Doxia Site Renderer
128                 throw new MojoExecutionException(e.getMessage(), e.getCause());
129             }
130             throw new MojoExecutionException(e.getMessage(), e);
131         } catch (IOException e) {
132             throw new MojoExecutionException("Error during site generation", e);
133         }
134     }
135 
136     private void renderLocale(Locale locale, List<MavenReportExecution> reports, List<Locale> supportedLocales)
137             throws IOException, RendererException, MojoFailureException, MojoExecutionException {
138         SiteRenderingContext context = createSiteRenderingContext(locale);
139         context.addSiteLocales(supportedLocales);
140         // MSITE-723 add generated site directory, in case some content has been put in pre-site phase
141         context.addSiteDirectory(generatedSiteDirectory);
142 
143         context.setInputEncoding(getInputEncoding());
144         context.setOutputEncoding(getOutputEncoding());
145         context.setValidate(validate);
146         if (validate) {
147             getLog().info("Validation is switched on, xml input documents will be validated!");
148         }
149 
150         File outputDir = getOutputDirectory(locale);
151 
152         Map<String, DocumentRenderer> documents = locateDocuments(context, reports, locale);
153 
154         // copy resources
155         siteRenderer.copyResources(context, outputDir);
156 
157         // 1. render Doxia documents first
158         List<DocumentRenderer> reportDocuments = renderDoxiaDocuments(documents, context, outputDir, false);
159 
160         // 2. then reports
161         // prepare external reports
162         for (MavenReportExecution mavenReportExecution : reports) {
163             MavenReport report = mavenReportExecution.getMavenReport();
164             report.setReportOutputDirectory(outputDir);
165         }
166 
167         siteRenderer.render(reportDocuments, context, outputDir);
168 
169         if (generateSitemap) {
170             getLog().info("Generating Sitemap.");
171 
172             new SiteMap(getOutputEncoding(), i18n).generate(context.getDecoration(), generatedSiteDirectory, locale);
173         }
174 
175         // 3. Generated docs must be (re-)done afterwards as they are often generated by reports
176         context.getSiteDirectories().clear();
177         context.addSiteDirectory(generatedSiteDirectory);
178 
179         Map<String, DocumentRenderer> generatedDocuments =
180                 siteRenderer.locateDocumentFiles(context, false /* not editable */);
181 
182         renderDoxiaDocuments(generatedDocuments, context, outputDir, true);
183 
184         // copy generated resources also
185         siteRenderer.copyResources(context, outputDir);
186     }
187 
188     /**
189      * Render Doxia documents from the list given, but not reports.
190      *
191      * @param documents a collection of documents containing both Doxia source files and reports
192      * @return the sublist of documents that are not Doxia source files
193      */
194     private List<DocumentRenderer> renderDoxiaDocuments(
195             Map<String, DocumentRenderer> documents, SiteRenderingContext context, File outputDir, boolean generated)
196             throws RendererException, IOException {
197         Map<String, DocumentRenderer> doxiaDocuments = new TreeMap<>();
198         List<DocumentRenderer> nonDoxiaDocuments = new ArrayList<>();
199 
200         Map<String, Integer> counts = new TreeMap<>();
201 
202         for (Map.Entry<String, DocumentRenderer> entry : documents.entrySet()) {
203             DocumentRenderer doc = entry.getValue();
204 
205             if (doc instanceof DoxiaDocumentRenderer) {
206                 doxiaDocuments.put(entry.getKey(), doc);
207 
208                 DoxiaDocumentRenderer doxia = (DoxiaDocumentRenderer) doc;
209 
210                 // count documents per parserId
211                 String parserId = doxia.getRenderingContext().getParserId();
212                 Integer count = counts.get(parserId);
213                 if (count == null) {
214                     count = 1;
215                 } else {
216                     count++;
217                 }
218                 counts.put(parserId, count);
219             } else {
220                 nonDoxiaDocuments.add(doc);
221             }
222         }
223 
224         if (doxiaDocuments.size() > 0) {
225             MessageBuilder mb = buffer();
226             mb.a("Rendering ");
227             mb.strong(doxiaDocuments.size() + (generated ? " generated" : "") + " Doxia document"
228                     + (doxiaDocuments.size() > 1 ? "s" : ""));
229             mb.a(": ");
230 
231             boolean first = true;
232             for (Map.Entry<String, Integer> entry : counts.entrySet()) {
233                 if (first) {
234                     first = false;
235                 } else {
236                     mb.a(", ");
237                 }
238                 mb.strong(entry.getValue() + " " + entry.getKey());
239             }
240 
241             getLog().info(mb.toString());
242 
243             siteRenderer.render(doxiaDocuments.values(), context, outputDir);
244         }
245 
246         return nonDoxiaDocuments;
247     }
248 
249     private File getOutputDirectory(Locale locale) {
250         File file;
251         if (locale.equals(SiteTool.DEFAULT_LOCALE)) {
252             file = outputDirectory;
253         } else {
254             file = new File(outputDirectory, locale.toString());
255         }
256 
257         // Safety
258         if (!file.exists()) {
259             file.mkdirs();
260         }
261 
262         return file;
263     }
264 
265     public MavenProject getProject() {
266         return project;
267     }
268 
269     public MavenSession getSession() {
270         return mavenSession;
271     }
272 }