View Javadoc
1   package org.apache.rat.mp;
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.artifact.Artifact;
23  import org.apache.maven.artifact.factory.ArtifactFactory;
24  import org.apache.maven.artifact.repository.ArtifactRepository;
25  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
26  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
27  import org.apache.maven.artifact.resolver.ArtifactResolver;
28  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
29  import org.apache.maven.artifact.versioning.VersionRange;
30  import org.apache.maven.doxia.site.decoration.Body;
31  import org.apache.maven.doxia.site.decoration.DecorationModel;
32  import org.apache.maven.doxia.site.decoration.Skin;
33  import org.apache.maven.doxia.siterenderer.Renderer;
34  import org.apache.maven.doxia.siterenderer.RendererException;
35  import org.apache.maven.doxia.siterenderer.RenderingContext;
36  import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
37  import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
38  import org.apache.maven.plugin.MojoExecutionException;
39  import org.apache.maven.plugin.MojoFailureException;
40  import org.apache.maven.plugins.annotations.Component;
41  import org.apache.maven.plugins.annotations.Mojo;
42  import org.apache.maven.plugins.annotations.Parameter;
43  import org.apache.maven.plugins.annotations.ResolutionScope;
44  import org.apache.maven.reporting.MavenReport;
45  import org.apache.maven.reporting.MavenReportException;
46  import org.apache.rat.Defaults;
47  import org.codehaus.doxia.sink.Sink;
48  
49  import java.io.File;
50  import java.io.FileWriter;
51  import java.io.IOException;
52  import java.io.Writer;
53  import java.util.HashMap;
54  import java.util.Iterator;
55  import java.util.Locale;
56  import java.util.Map;
57  import java.util.ResourceBundle;
58  
59  
60  /**
61   * Generates a report with Rat's output.
62   */
63  @SuppressWarnings("deprecation") // MavenReport invokes the deprecated Sink implementation
64  @Mojo(name = "rat", requiresDependencyResolution = ResolutionScope.TEST)
65  public class RatReportMojo extends AbstractRatMojo implements MavenReport {
66      public static final String DOT_HTML = ".html";
67      @Component
68      private Renderer siteRenderer;
69  
70      @Component
71      private ArtifactFactory factory;
72  
73      @Component
74      private ArtifactResolver resolver;
75  
76      /**
77       * Specifies the directory where the report will be generated
78       */
79      @Parameter(defaultValue = "${project.reporting.outputDirectory}", required = true)
80      private File outputDirectory;
81  
82      @Parameter(defaultValue = "${localRepository}", required = true, readonly = true)
83      private ArtifactRepository localRepository;
84  
85      /**
86       * Returns the skins artifact file.
87       *
88       * @return Artifact file
89       * @throws MojoFailureException   An error in the plugin configuration was detected.
90       * @throws MojoExecutionException An error occurred while searching for the artifact file.
91       */
92      private File getSkinArtifactFile() throws MojoFailureException, MojoExecutionException {
93          final Skin skin = Skin.getDefaultSkin();
94  
95          String version = skin.getVersion();
96          final Artifact artifact;
97          try {
98              if (version == null) {
99                  version = Artifact.RELEASE_VERSION;
100             }
101             VersionRange versionSpec = VersionRange.createFromVersionSpec(version);
102             artifact =
103                     factory.createDependencyArtifact(skin.getGroupId(), skin.getArtifactId(), versionSpec, "jar", null,
104                             null);
105 
106             resolver.resolve(artifact, getProject().getRemoteArtifactRepositories(), localRepository);
107         } catch (InvalidVersionSpecificationException e) {
108             throw new MojoFailureException("The skin version '" + version + "' is not valid: " + e.getMessage());
109         } catch (ArtifactResolutionException e) {
110             throw new MojoExecutionException("Unable to find skin", e);
111         } catch (ArtifactNotFoundException e) {
112             throw new MojoFailureException("The skin does not exist: " + e.getMessage());
113         }
114 
115         return artifact.getFile();
116     }
117 
118     /**
119      * Called from Maven to invoke the plugin.
120      *
121      * @throws MojoFailureException   An error in the plugin configuration was detected.
122      * @throws MojoExecutionException An error occurred while creating the report.
123      */
124     public void execute() throws MojoExecutionException, MojoFailureException {
125         if (skip) {
126             getLog().info("RAT will not execute since it is configured to be skipped via system property 'rat.skip'.");
127             return;
128         }
129 
130         final DecorationModel model = new DecorationModel();
131         model.setBody(new Body());
132         final Map<String, String> attributes = new HashMap<String, String>();
133         attributes.put("outputEncoding", "UTF-8");
134         final Locale locale = Locale.getDefault();
135         try {
136             final SiteRenderingContext siteContext =
137                     siteRenderer.createContextForSkin(getSkinArtifactFile(), attributes, model, getName(locale),
138                             locale);
139             final RenderingContext context = new RenderingContext(outputDirectory, getOutputName() + DOT_HTML);
140 
141             final SiteRendererSink sink = new SiteRendererSink(context);
142             generate(sink, locale);
143 
144             if (!outputDirectory.mkdirs() && !outputDirectory.isDirectory()) {
145                 throw new IOException("Could not create output directory " + outputDirectory);
146             }
147 
148 
149             final Writer writer = new FileWriter(new File(outputDirectory, getOutputName() + DOT_HTML));
150 
151             siteRenderer.generateDocument(writer, sink, siteContext);
152 
153             siteRenderer.copyResources(siteContext, new File(getProject().getBasedir(), "src/site/resources"),
154                     outputDirectory);
155         } catch (IOException e) {
156             throw new MojoExecutionException(e.getMessage(), e);
157         } catch (MavenReportException e) {
158             throw new MojoExecutionException(e.getMessage(), e);
159         } catch (RendererException e) {
160             throw new MojoExecutionException(e.getMessage(), e);
161         }
162     }
163 
164     /**
165      * Returns, whether the report may be generated.
166      *
167      * @return Always true.
168      */
169     public boolean canGenerateReport() {
170         return true;
171     }
172 
173     /**
174      * Searches for a Rat artifact in the dependency list and returns its version.
175      *
176      * @return Version number, if found, or null.
177      */
178     private String getRatVersion() {
179         for (@SuppressWarnings("unchecked") // library is not yet generified
180              Iterator<Artifact> iter = getProject().getDependencyArtifacts().iterator(); iter.hasNext(); ) {
181             Artifact a = iter.next();
182             if ("rat-lib".equals(a.getArtifactId())) {
183                 return a.getVersion();
184             }
185         }
186         return null;
187     }
188 
189     /**
190      * Writes the report to the Doxia sink.
191      *
192      * @param sink   The doxia sink, kind of a SAX handler.
193      * @param locale The locale to use for writing the report.
194      * @throws MavenReportException Writing the report failed.
195      */
196     public void generate(Sink sink, Locale locale) throws MavenReportException {
197         ResourceBundle bundle = getBundle(locale);
198         final String title = bundle.getString("report.rat.title");
199         sink.head();
200         sink.title();
201         sink.text(title);
202         sink.title_();
203         sink.head_();
204 
205         sink.body();
206 
207         sink.section1();
208         sink.sectionTitle1();
209         sink.text(title);
210         sink.sectionTitle1_();
211 
212         sink.paragraph();
213         sink.text(bundle.getString("report.rat.link") + " ");
214         sink.link(bundle.getString("report.rat.url"));
215         sink.text(bundle.getString("report.rat.fullName"));
216         sink.link_();
217         final String ratVersion = getRatVersion();
218         if (ratVersion != null) {
219             sink.text(" " + ratVersion);
220         }
221         sink.text(".");
222         sink.paragraph_();
223 
224         sink.paragraph();
225         sink.verbatim(true);
226         try {
227             sink.text(createReport(Defaults.getDefaultStyleSheet()));
228         } catch (MojoExecutionException e) {
229             throw new MavenReportException(e.getMessage(), e);
230         } catch (MojoFailureException e) {
231             throw new MavenReportException(e.getMessage(), e);
232         }
233         sink.verbatim_();
234         sink.paragraph_();
235         sink.section1_();
236         sink.body_();
237     }
238 
239     /**
240      * Returns the reports category name.
241      *
242      * @return {@link MavenReport#CATEGORY_PROJECT_REPORTS}
243      */
244     public String getCategoryName() {
245         return MavenReport.CATEGORY_PROJECT_REPORTS;
246     }
247 
248     /**
249      * Returns the reports bundle
250      *
251      * @param locale Requested locale of the bundle
252      * @return The bundle, which is used to read localized strings.
253      */
254     private ResourceBundle getBundle(Locale locale) {
255         return ResourceBundle.getBundle("org/apache/rat/mp/rat-report", locale, getClass().getClassLoader());
256     }
257 
258     /**
259      * Returns the reports description.
260      *
261      * @param locale Requested locale of the bundle
262      * @return Report description, as given by the key "report.rat.description" in the bundle.
263      */
264     public String getDescription(Locale locale) {
265         return getBundle(locale).getString("report.rat.description");
266     }
267 
268     /**
269      * Returns the reports name.
270      *
271      * @param locale Requested locale of the bundle
272      * @return Report name, as given by the key "report.rat.name" in the bundle.
273      */
274     public String getName(Locale locale) {
275         return getBundle(locale).getString("report.rat.name");
276     }
277 
278     /**
279      * Returns the reports file name.
280      *
281      * @return "rat-report"
282      */
283     public String getOutputName() {
284         return "rat-report";
285     }
286 
287     /**
288      * Returns the reports output directory.
289      *
290      * @return Value of the "outputDirectory" parameter.
291      */
292     public File getReportOutputDirectory() {
293         return outputDirectory;
294     }
295 
296     /**
297      * Returns, whether this is an external report.
298      *
299      * @return Always false.
300      */
301     public boolean isExternalReport() {
302         return false;
303     }
304 
305     /**
306      * Sets the reports output directory.
307      *
308      * @param pOutputDirectory Reports target directory.
309      */
310     public void setReportOutputDirectory(File pOutputDirectory) {
311         outputDirectory = pOutputDirectory;
312     }
313 }