View Javadoc
1   package org.codehaus.mojo.clirr;
2   
3   /*
4    * Copyright 2006 The Codehaus
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * 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, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import net.sf.clirr.core.Severity;
20  
21  import org.apache.maven.artifact.Artifact;
22  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
23  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
24  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
25  import org.apache.maven.artifact.versioning.VersionRange;
26  import org.apache.maven.doxia.module.xhtml.decoration.render.RenderingContext;
27  import org.apache.maven.doxia.sink.Sink;
28  import org.apache.maven.doxia.site.decoration.Body;
29  import org.apache.maven.doxia.site.decoration.DecorationModel;
30  import org.apache.maven.doxia.site.decoration.Skin;
31  import org.apache.maven.doxia.siterenderer.Renderer;
32  import org.apache.maven.doxia.siterenderer.RendererException;
33  import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
34  import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
35  import org.apache.maven.model.ReportPlugin;
36  import org.apache.maven.plugin.MojoExecutionException;
37  import org.apache.maven.plugin.MojoFailureException;
38  import org.apache.maven.reporting.MavenReport;
39  import org.apache.maven.reporting.MavenReportException;
40  import org.codehaus.plexus.i18n.I18N;
41  import org.codehaus.plexus.util.PathTool;
42  import org.codehaus.plexus.util.StringUtils;
43  
44  import java.io.File;
45  import java.io.FileWriter;
46  import java.io.IOException;
47  import java.io.Writer;
48  import java.util.HashMap;
49  import java.util.Iterator;
50  import java.util.Locale;
51  import java.util.Map;
52  import java.util.ResourceBundle;
53  
54  /**
55   * Generate a report from the Clirr output.
56   *
57   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
58   * @goal clirr
59   * @execute phase="compile"
60   */
61  public class ClirrReport
62      extends AbstractClirrMojo
63      implements MavenReport
64  {
65      /**
66       * Specifies the directory where the report will be generated.
67       *
68       * @parameter default-value="${project.reporting.outputDirectory}"
69       * @required
70       */
71      private File outputDirectory;
72  
73      /**
74       * @component
75       */
76      private Renderer siteRenderer;
77  
78      /**
79       * Whether to show the summary of the number of errors, warnings and informational messages.
80       *
81       * @parameter property="showSummary" default-value="true"
82       */
83      private boolean showSummary;
84  
85      /**
86       * Whether to render the HTML report or not.
87       *
88       * @parameter property="htmlReport" default-value="true"
89       */
90      private boolean htmlReport;
91  
92      /**
93       * Link the violation line numbers to the source Xref. This will create links
94       * if the JXR Plugin is being used.
95       *
96       * @parameter property="linkXRef" default-value="true"
97       */
98      private boolean linkXRef;
99  
100     /**
101      * Location of the Xrefs to link to.
102      *
103      * @parameter property="xrefLocation" default-value="${project.build.directory}/site/xref"
104      */
105     private File xrefLocation;
106 
107     /**
108      * @component
109      */
110     private I18N i18n;
111 
112     public String getCategoryName()
113     {
114         return MavenReport.CATEGORY_PROJECT_REPORTS;
115     }
116 
117     public void setReportOutputDirectory( File file )
118     {
119         outputDirectory = file;
120     }
121 
122     public File getReportOutputDirectory()
123     {
124         return outputDirectory;
125     }
126 
127     public boolean isExternalReport()
128     {
129         return false;
130     }
131 
132     private File getSkinArtifactFile()
133         throws MojoFailureException, MojoExecutionException
134     {
135         Skin skin = Skin.getDefaultSkin();
136 
137         String version = skin.getVersion();
138         Artifact artifact;
139         try
140         {
141             if ( version == null )
142             {
143                 version = Artifact.RELEASE_VERSION;
144             }
145             VersionRange versionSpec = VersionRange.createFromVersionSpec( version );
146             artifact = factory.createDependencyArtifact( skin.getGroupId(), skin.getArtifactId(), versionSpec, "jar",
147                                                          null, null );
148 
149             resolver.resolve( artifact, project.getRemoteArtifactRepositories(), localRepository );
150         }
151         catch ( InvalidVersionSpecificationException e )
152         {
153             throw new MojoFailureException( "The skin version '" + version + "' is not valid: " + e.getMessage() );
154         }
155         catch ( ArtifactResolutionException e )
156         {
157             throw new MojoExecutionException( "Unable to find skin", e );
158         }
159         catch ( ArtifactNotFoundException e )
160         {
161             throw new MojoFailureException( "The skin does not exist: " + e.getMessage() );
162         }
163 
164         return artifact.getFile();
165     }
166 
167     @Override
168     protected void doExecute()
169         throws MojoExecutionException, MojoFailureException
170     {
171         if ( !canGenerateReport() )
172         {
173             return;
174         }
175 
176         // TODO: push to a helper? Could still be improved by taking more of the site information from the site plugin
177         try
178         {
179             DecorationModel model = new DecorationModel();
180             model.setBody( new Body() );
181             Map attributes = new HashMap();
182             attributes.put( "outputEncoding", "UTF-8" );
183             Locale locale = Locale.getDefault();
184             SiteRenderingContext siteContext = siteRenderer.createContextForSkin( getSkinArtifactFile(), attributes,
185                                                                                   model, getName( locale ), locale );
186 
187             RenderingContext context = new RenderingContext( outputDirectory, getOutputName() + ".html" );
188 
189             SiteRendererSink sink = new SiteRendererSink( context );
190             generate( sink, locale );
191 
192             outputDirectory.mkdirs();
193 
194             Writer writer = new FileWriter( new File( outputDirectory, getOutputName() + ".html" ) );
195 
196             siteRenderer.generateDocument( writer, sink, siteContext );
197 
198             siteRenderer.copyResources( siteContext, new File( project.getBasedir(), "src/site/resources" ),
199                                         outputDirectory );
200         }
201         catch ( RendererException e )
202         {
203             throw new MojoExecutionException(
204                 "An error has occurred in " + getName( Locale.ENGLISH ) + " report generation.", e );
205         }
206         catch ( IOException e )
207         {
208             throw new MojoExecutionException(
209                 "An error has occurred in " + getName( Locale.ENGLISH ) + " report generation.", e );
210         }
211         catch ( MavenReportException e )
212         {
213             throw new MojoExecutionException(
214                 "An error has occurred in " + getName( Locale.ENGLISH ) + " report generation.", e );
215         }
216     }
217 
218     public void generate( Sink sink, Locale locale )
219         throws MavenReportException
220     {
221         if ( !canGenerateReport() )
222         {
223             getLog().info( "Not generating report as there are no sources to compare" );
224         }
225         else
226         {
227             doReport( sink, locale );
228         }
229     }
230 
231     private void doReport( Sink sink, Locale locale )
232         throws MavenReportException
233     {
234         Severity minSeverity = convertSeverity( this.minSeverity );
235         ResourceBundle bundle = getBundle( locale );
236         if ( minSeverity == null )
237         {
238             getLog().warn( bundle.getString( "report.clirr.error.invalid.minseverity" ) + ": '" + this
239                 .minSeverity + "'." );
240         }
241 
242         if ( !htmlReport && xmlOutputFile == null && textOutputFile == null && !logResults )
243         {
244             getLog().error( bundle.getString( "report.clirr.error.noreports" ) );
245         }
246         else
247         {
248             ClirrDiffListener listener;
249             try
250             {
251                 listener = executeClirr( minSeverity );
252             }
253             catch ( MissingPreviousException e )
254             {
255                 getLog().error( bundle.getString( "report.clirr.error.nopredecessor" ) );
256                 return;
257             }
258             catch ( MojoExecutionException e )
259             {
260                 throw new MavenReportException( e.getMessage(), e );
261             }
262             catch ( MojoFailureException e )
263             {
264                 throw new MavenReportException( e.getMessage() );
265             }
266 
267             if ( htmlReport )
268             {
269                 ClirrReportGenerator generator = new ClirrReportGenerator( sink, i18n, bundle, locale );
270 
271                 generator.setEnableSeveritySummary( showSummary );
272 
273                 generator.setMinSeverity( minSeverity );
274 
275                 generator.setCurrentVersion( project.getVersion() );
276 
277                 if ( comparisonVersion != null )
278                 {
279                     generator.setComparisonVersion( comparisonVersion );
280                 }
281 
282                 if ( linkXRef )
283                 {
284                     String relativePath =
285                         PathTool.getRelativePath( outputDirectory.getAbsolutePath(), xrefLocation.getAbsolutePath() );
286                     if ( StringUtils.isEmpty( relativePath ) )
287                     {
288                         relativePath = ".";
289                     }
290                     relativePath = relativePath + "/" + xrefLocation.getName();
291                     if ( xrefLocation.exists() )
292                     {
293                         // XRef was already generated by manual execution of a lifecycle binding
294                         generator.setXrefLocation( relativePath );
295                     }
296                     else
297                     {
298                         // Not yet generated - check if the report is on its way
299                         for ( Iterator reports = project.getReportPlugins().iterator(); reports.hasNext(); )
300                         {
301                             ReportPlugin report = (ReportPlugin) reports.next();
302 
303                             String artifactId = report.getArtifactId();
304                             if ( "maven-jxr-plugin".equals( artifactId ) || "jxr-maven-plugin".equals( artifactId ) )
305                             {
306                                 generator.setXrefLocation( relativePath );
307                             }
308                         }
309                     }
310 
311                     if ( generator.getXrefLocation() == null )
312                     {
313                         getLog().warn( "Unable to locate Source XRef to link to - DISABLED" );
314                     }
315                 }
316                 generator.generateReport( listener );
317             }
318         }
319     }
320 
321     public String getDescription( Locale locale )
322     {
323         return getBundle( locale ).getString( "report.clirr.description" );
324     }
325 
326     public String getName( Locale locale )
327     {
328         return getBundle( locale ).getString( "report.clirr.name" );
329     }
330 
331     public String getOutputName()
332     {
333         return "clirr-report";
334     }
335 
336     private ResourceBundle getBundle( Locale locale )
337     {
338         return ResourceBundle.getBundle( "clirr-report", locale, getClass().getClassLoader() );
339     }
340 
341     public boolean canGenerateReport()
342     {
343         try
344         {
345             if ( skip )
346             {
347                 getLog().info( "Skipping execution" );
348                 return false;
349             }
350             return canGenerate();
351         }
352         catch ( MojoFailureException e )
353         {
354             getLog().error( "Can't generate Clirr report: " + e.getMessage() );
355             return false;
356         }
357         catch ( MojoExecutionException e )
358         {
359             getLog().error( "Can't generate Clirr report: " + e.getMessage(), e );
360             return false;
361         }
362     }
363 
364     // eventually, we must replace this with the o.a.m.d.s.Sink class as a parameter
365     public void generate( org.codehaus.doxia.sink.Sink sink, Locale locale )
366         throws MavenReportException
367     {
368         generate( (Sink) sink, locale );
369 
370     }
371 }