View Javadoc
1   /*
2    * Copyright 2016-2017 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.github.matinh.vdldoc.maven.plugins;
18  
19  import org.apache.maven.plugin.AbstractMojo;
20  import org.apache.maven.plugin.MojoExecutionException;
21  import org.apache.maven.plugins.annotations.Execute;
22  import org.apache.maven.plugins.annotations.LifecyclePhase;
23  import org.apache.maven.plugins.annotations.Mojo;
24  import org.apache.maven.plugins.annotations.Parameter;
25  import org.apache.maven.reporting.MavenReport;
26  import org.apache.maven.reporting.MavenReportException;
27  import org.codehaus.doxia.sink.Sink;
28  import org.codehaus.plexus.util.StringUtils;
29  import org.omnifaces.vdldoc.VdldocGenerator;
30  
31  import java.io.File;
32  import java.util.ArrayList;
33  import java.util.Collections;
34  import java.util.List;
35  import java.util.Locale;
36  import java.util.ResourceBundle;
37  
38  /**
39   * Generate documentation for JSF tag libraries via OmniFaces Vdldoc.
40   *
41   * @author martin
42   * @since 1.0-alpha-1
43   */
44  @Mojo(name = "vdldoc", defaultPhase = LifecyclePhase.SITE)
45  @Execute(phase = LifecyclePhase.GENERATE_SOURCES)
46  public class Vdldoc
47      extends AbstractMojo
48      implements MavenReport
49  {
50      /**
51       * Browser window title.
52       */
53      @Parameter(defaultValue = "${project.name} VDL Documentation")
54      private String browserTitle;
55  
56      /**
57       * Documentation title.
58       */
59      @Parameter(defaultValue = "${project.name} VDL Documentation")
60      private String documentTitle;
61  
62      /**
63       * If {@code false}, build will continue when generation of documentation
64       * fails.
65       */
66      // we initialize to default value here for unit testing.
67      @Parameter(defaultValue = "true", property = "maven.vdldoc.failOnError")
68      private boolean failOnError = true;
69  
70      /**
71       * Skip the generation of VDL documentation.
72       */
73      @Parameter(defaultValue = "false", property = "maven.vdldoc.skip")
74      private boolean skip;
75  
76      /**
77       * Patterns to include when searching for taglib descriptor files.
78       */
79      @Parameter(defaultValue = "**/*.taglib.xml",
80          property = "maven.vdldoc.includes")
81      private List<String> includes;
82  
83      /**
84       * Patterns to exclude when searching for taglib descriptor files.
85       */
86      @Parameter(defaultValue = "target/**", property = "maven.vdldoc.excludes")
87      private List<String> excludes;
88  
89      /**
90       * Location of the output directory for the generated report.
91       * This configuration is usually only useful if you call the mojo directly
92       * from the command-line.
93       */
94      @Parameter(defaultValue = "${project.reporting.outputDirectory}",
95          property = "maven.vdldoc.outputDirectory")
96      private File reportOutputDirectory;
97  
98      /**
99       * Name of the directory (inside the reporting-output-directory) into which
100      * Vdldoc will place the generated documentation.
101      */
102     // we initialize to default value here for unit testing.
103     @Parameter(defaultValue = "vdldoc", property = "maven.vdldoc.destDir")
104     private String destDir = "vdldoc";
105 
106     /**
107      * URI of the CSS file. This defaults to Vdldocs internal CSS.
108      * @since 1.0
109      */
110     @Parameter(property = "maven.vdldoc.css")
111     private String css;
112 
113     /**
114      * Path to the faces-config.xml file.
115      * @since 1.0
116      */
117     @Parameter(property = "maven.vdldoc.facesConfig")
118     private String facesConfig;
119 
120     /**
121      * Path to properties file containing descriptions for implied attributes
122      * of composite components, such as 'id', 'rendered', etc.
123      * @since 1.0
124      */
125     @Parameter(property = "maven.vdldoc.attributesFile")
126     private String attributesFile;
127 
128     /**
129      * Hide the "output generated by" footer.
130      * @since 1.0
131      */
132     @Parameter(defaultValue = "false",
133         property = "maven.vdldoc.hideGeneratedBy")
134     private boolean hideGeneratedBy;
135 
136 
137     // ============ end of writable mojo parameters ===========
138 
139     /**
140      * The directory to scan for taglib files.
141      */
142     @Parameter(defaultValue = "${project.basedir}", readonly = true)
143     private File srcDirectory;
144 
145     /**
146      * The documentation generator to use.
147      */
148     private VdldocGenerator generator = new VdldocGenerator();
149 
150 
151     /**
152      * Set the generator to use for documentation generation.
153      * <p>
154      * This method is meant for unit tests only.
155      * </p>
156      * @param gen The generator to use. Must not be {@code null}.
157      */
158     void setGenerator(final VdldocGenerator gen)
159     {
160         this.generator = gen;
161     }
162 
163     @Override
164     public void execute() throws MojoExecutionException
165     {
166         if (skip) {
167             getLog().info("Skipping generation of Vdldoc.");
168             return;
169         }
170 
171         try {
172             generateDocumentation();
173         } catch (Exception e) {
174             if (failOnError) {
175                 throw new MojoExecutionException("Error generating Vdldoc!", e);
176             }
177 
178             // log the failure and continue
179             final String reason = e.getLocalizedMessage() == null
180                 ? e.toString() : e.getLocalizedMessage();
181             getLog().warn("Failed to generate documentation: "
182                 + reason);
183             getLog().debug(e);
184         }
185     }
186 
187     @SuppressWarnings("deprecation")
188     @Override
189     public void generate(final Sink sink, final Locale locale)
190         throws MavenReportException
191     {
192         try {
193             execute();
194         } catch (MojoExecutionException e) {
195             throw new MavenReportException(e.getMessage(),
196                 (Exception) e.getCause());
197         }
198     }
199 
200     @Override
201     public String getOutputName()
202     {
203         return destDir + File.separator + "index";
204     }
205 
206     @Override
207     public String getCategoryName()
208     {
209         return CATEGORY_PROJECT_REPORTS;
210     }
211 
212     @Override
213     public String getName(final Locale locale)
214     {
215         return getBundle(locale).getString("report.vdldoc.name");
216     }
217 
218     @Override
219     public String getDescription(final Locale locale)
220     {
221         return getBundle(locale).getString("report.vdldoc.description");
222     }
223 
224     @Override
225     public void setReportOutputDirectory(final File file)
226     {
227         reportOutputDirectory = file;
228     }
229 
230     @Override
231     public File getReportOutputDirectory()
232     {
233         return reportOutputDirectory;
234     }
235 
236     @Override
237     public boolean isExternalReport()
238     {
239         return true;
240     }
241 
242     @Override
243     public boolean canGenerateReport()
244     {
245         return true;
246     }
247 
248     /**
249      * Gets the resource bundle for the specified locale.
250      *
251      * @param locale The locale of the currently generated report.
252      * @return The resource bundle for the requested locale.
253      */
254     private ResourceBundle getBundle(final Locale locale)
255     {
256         return ResourceBundle.getBundle(
257             "vdldoc-report", locale, getClass().getClassLoader());
258     }
259 
260     private void generateDocumentation()
261     {
262         generator.setWindowTitle(browserTitle);
263         generator.setDocTitle(documentTitle);
264         generator.setOutputDirectory(new File(reportOutputDirectory, destDir));
265 
266         if (!StringUtils.isEmpty(css)) {
267             getLog().debug("Using CSS file " + css);
268             generator.setCssLocation(css);
269         }
270 
271         if (!StringUtils.isEmpty(facesConfig)) {
272             getLog().debug("Using faces-config file "
273                 + facesConfig);
274             generator.setFacesConfig(new File(facesConfig));
275         }
276         if (!StringUtils.isEmpty(attributesFile)) {
277             getLog().debug("Using attributes-file "
278                 + attributesFile);
279             generator.setAttributes(new File(attributesFile));
280         }
281         if (hideGeneratedBy) {
282             getLog().debug("Hiding 'generated-by' message.");
283             generator.setHideGeneratedBy(true);
284         }
285 
286         // TODO add support for quiet-flag
287 
288         final List<String> taglibs = scanForTaglibs(
289             srcDirectory, includes, excludes);
290         getLog().debug("Found taglibs: " + taglibs);
291         for (String taglib : taglibs) {
292             generator.addTaglib(new File(srcDirectory, taglib));
293         }
294 
295         generator.generate();
296     }
297 
298     private List<String> scanForTaglibs(final File basedir,
299         final List<String> includeList, final List<String> excludeList)
300     {
301         List<String> result = new ArrayList<>();
302         if (basedir != null && basedir.exists()) {
303             org.codehaus.plexus.util.DirectoryScanner scanner =
304                 new org.codehaus.plexus.util.DirectoryScanner();
305 
306             scanner.setBasedir(basedir);
307 
308             if (includeList != null) {
309                 scanner.setIncludes(processIncludesExcludes(includeList));
310             }
311 
312             if (excludeList != null) {
313                 scanner.setExcludes(processIncludesExcludes(excludeList));
314             }
315 
316             scanner.scan();
317             Collections.addAll(result, scanner.getIncludedFiles());
318         }
319         return result;
320     }
321 
322     // based on maven-surefire-plugin's DirectoryScanner
323     private static String[] processIncludesExcludes(final List<String> list)
324     {
325         List<String> newList = new ArrayList<>();
326         for (String aList : list) {
327             String[] includes = aList.split(",");
328             Collections.addAll(newList, includes);
329         }
330 
331         String[] incs = new String[newList.size()];
332         for (int i = 0; i < incs.length; i++) {
333             incs[i] = newList.get(i);
334         }
335 
336         return incs;
337     }
338 }