1 package org.apache.maven.plugin.checkstyle;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import com.puppycrawl.tools.checkstyle.DefaultLogger;
23 import com.puppycrawl.tools.checkstyle.XMLLogger;
24 import com.puppycrawl.tools.checkstyle.api.AuditListener;
25 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
26 import org.apache.maven.doxia.siterenderer.Renderer;
27 import org.apache.maven.doxia.tools.SiteTool;
28 import org.apache.maven.model.ReportPlugin;
29 import org.apache.maven.model.Resource;
30 import org.apache.maven.plugin.checkstyle.rss.CheckstyleRssGenerator;
31 import org.apache.maven.plugin.checkstyle.rss.CheckstyleRssGeneratorRequest;
32 import org.apache.maven.plugins.annotations.Component;
33 import org.apache.maven.plugins.annotations.Parameter;
34 import org.apache.maven.project.MavenProject;
35 import org.apache.maven.reporting.AbstractMavenReport;
36 import org.apache.maven.reporting.MavenReportException;
37 import org.codehaus.plexus.resource.ResourceManager;
38 import org.codehaus.plexus.resource.loader.FileResourceLoader;
39 import org.codehaus.plexus.util.PathTool;
40 import org.codehaus.plexus.util.StringUtils;
41
42 import java.io.ByteArrayOutputStream;
43 import java.io.File;
44 import java.io.FileNotFoundException;
45 import java.io.FileOutputStream;
46 import java.io.IOException;
47 import java.io.OutputStream;
48 import java.util.Calendar;
49 import java.util.Iterator;
50 import java.util.List;
51 import java.util.Locale;
52 import java.util.ResourceBundle;
53
54
55
56
57
58
59
60 public abstract class AbstractCheckstyleReport
61 extends AbstractMavenReport
62 {
63 public static final String PLUGIN_RESOURCES = "org/apache/maven/plugin/checkstyle";
64
65 protected static final String JAVA_FILES = "**\\/*.java";
66
67
68
69
70
71
72 @Parameter( property = "checkstyle.skip", defaultValue = "false" )
73 protected boolean skip;
74
75
76
77
78
79
80
81 @Parameter( defaultValue = "${project.reporting.outputDirectory}", required = true )
82 private File outputDirectory;
83
84
85
86
87
88
89 @Parameter( property = "checkstyle.output.file", defaultValue = "${project.build.directory}/checkstyle-result.xml" )
90 private File outputFile;
91
92
93
94
95
96
97 @Parameter( defaultValue = "${project.resources}", readonly = true )
98 protected List<Resource> resources;
99
100
101
102
103
104 @Parameter
105 private File useFile;
106
107
108
109
110
111 @Parameter( property = "checkstyle.output.format", defaultValue = "xml" )
112 private String outputFileFormat;
113
114
115
116
117 @Parameter( property = "checkstyle.enable.rules.summary", defaultValue = "true" )
118 private boolean enableRulesSummary;
119
120
121
122
123 @Parameter( property = "checkstyle.enable.severity.summary", defaultValue = "true" )
124 private boolean enableSeveritySummary;
125
126
127
128
129 @Parameter( property = "checkstyle.enable.files.summary", defaultValue = "true" )
130 private boolean enableFilesSummary;
131
132
133
134
135 @Parameter( property = "checkstyle.enable.rss", defaultValue = "true" )
136 private boolean enableRSS;
137
138
139
140
141
142
143 @Component( role = SiteTool.class )
144 protected SiteTool siteTool;
145
146
147
148
149 @Component
150 protected MavenProject project;
151
152
153
154
155
156
157
158 @Parameter( property = "linkXRef", defaultValue = "true" )
159 private boolean linkXRef;
160
161
162
163
164 @Parameter( defaultValue = "${project.reporting.outputDirectory}/xref" )
165 private File xrefLocation;
166
167
168
169 @Component
170 private Renderer siteRenderer;
171
172
173
174 @Component
175 protected ResourceManager locator;
176
177
178
179
180
181
182 @Component( role = CheckstyleRssGenerator.class, hint = "default" )
183 protected CheckstyleRssGenerator checkstyleRssGenerator;
184
185
186
187
188 @Component( role = CheckstyleExecutor.class, hint = "default" )
189 protected CheckstyleExecutor checkstyleExecutor;
190
191 protected ByteArrayOutputStream stringOutputStream;
192
193
194 public String getName( Locale locale )
195 {
196 return getBundle( locale ).getString( "report.checkstyle.name" );
197 }
198
199
200 public String getDescription( Locale locale )
201 {
202 return getBundle( locale ).getString( "report.checkstyle.description" );
203 }
204
205
206 protected String getOutputDirectory()
207 {
208 return outputDirectory.getAbsolutePath();
209 }
210
211
212 protected MavenProject getProject()
213 {
214 return project;
215 }
216
217
218 protected Renderer getSiteRenderer()
219 {
220 return siteRenderer;
221 }
222
223
224 public void executeReport( Locale locale )
225 throws MavenReportException
226 {
227 locator.addSearchPath( FileResourceLoader.ID, project.getFile().getParentFile().getAbsolutePath() );
228 locator.addSearchPath( "url", "" );
229
230 locator.setOutputDirectory( new File( project.getBuild().getDirectory() ) );
231
232
233
234
235
236
237
238
239 ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
240
241 try
242 {
243 CheckstyleExecutorRequest request = createRequest();
244
245 CheckstyleResults results = checkstyleExecutor.executeCheckstyle( request );
246
247 ResourceBundle bundle = getBundle( locale );
248 generateReportStatics();
249 generateMainReport( results, bundle );
250 if ( enableRSS )
251 {
252 CheckstyleRssGeneratorRequest checkstyleRssGeneratorRequest =
253 new CheckstyleRssGeneratorRequest( this.project, this.getCopyright(), outputDirectory, getLog() );
254 checkstyleRssGenerator.generateRSS( results, checkstyleRssGeneratorRequest );
255 }
256
257 }
258 catch ( CheckstyleException e )
259 {
260 throw new MavenReportException( "Failed during checkstyle configuration", e );
261 }
262 catch ( CheckstyleExecutorException e )
263 {
264 throw new MavenReportException( "Failed during checkstyle execution", e );
265 }
266 finally
267 {
268
269 Thread.currentThread().setContextClassLoader( currentClassLoader );
270 }
271 }
272
273
274
275
276
277
278
279 protected abstract CheckstyleExecutorRequest createRequest()
280 throws MavenReportException;
281
282
283
284
285
286
287
288 protected AuditListener getListener()
289 throws MavenReportException
290 {
291 AuditListener listener = null;
292
293 if ( StringUtils.isNotEmpty( outputFileFormat ) )
294 {
295 File resultFile = outputFile;
296
297 OutputStream out = getOutputStream( resultFile );
298
299 if ( "xml".equals( outputFileFormat ) )
300 {
301 listener = new XMLLogger( out, true );
302 }
303 else if ( "plain".equals( outputFileFormat ) )
304 {
305 listener = new DefaultLogger( out, true );
306 }
307 else
308 {
309
310 throw new MavenReportException( "Invalid output file format: (" + outputFileFormat
311 + "). Must be 'plain' or 'xml'." );
312 }
313 }
314
315 return listener;
316 }
317
318 private OutputStream getOutputStream( File file )
319 throws MavenReportException
320 {
321 File parentFile = file.getAbsoluteFile().getParentFile();
322
323 if ( !parentFile.exists() )
324 {
325 parentFile.mkdirs();
326 }
327
328 FileOutputStream fileOutputStream;
329 try
330 {
331 fileOutputStream = new FileOutputStream( file );
332 }
333 catch ( FileNotFoundException e )
334 {
335 throw new MavenReportException( "Unable to create output stream: " + file, e );
336 }
337 return fileOutputStream;
338 }
339
340
341
342
343
344
345
346 protected DefaultLogger getConsoleListener()
347 throws MavenReportException
348 {
349 DefaultLogger consoleListener;
350
351 if ( useFile == null )
352 {
353 stringOutputStream = new ByteArrayOutputStream();
354 consoleListener = new DefaultLogger( stringOutputStream, false );
355 }
356 else
357 {
358 OutputStream out = getOutputStream( useFile );
359
360 consoleListener = new DefaultLogger( out, true );
361 }
362
363 return consoleListener;
364 }
365
366 private void generateReportStatics()
367 throws MavenReportException
368 {
369 ReportResource rresource = new ReportResource( PLUGIN_RESOURCES, outputDirectory );
370 try
371 {
372 rresource.copy( "images/rss.png" );
373 }
374 catch ( IOException e )
375 {
376 throw new MavenReportException( "Unable to copy static resources.", e );
377 }
378 }
379
380
381 private String getCopyright()
382 {
383 String copyright;
384 int currentYear = Calendar.getInstance().get( Calendar.YEAR );
385 if ( StringUtils.isNotEmpty( project.getInceptionYear() )
386 && !String.valueOf( currentYear ).equals( project.getInceptionYear() ) )
387 {
388 copyright = project.getInceptionYear() + " - " + currentYear;
389 }
390 else
391 {
392 copyright = String.valueOf( currentYear );
393 }
394
395 if ( ( project.getOrganization() != null ) && StringUtils.isNotEmpty( project.getOrganization().getName() ) )
396 {
397 copyright = copyright + " " + project.getOrganization().getName();
398 }
399 return copyright;
400 }
401
402 private void generateMainReport( CheckstyleResults results, ResourceBundle bundle )
403 {
404 CheckstyleReportGenerator generator =
405 new CheckstyleReportGenerator( getSink(), bundle, project.getBasedir(), siteTool );
406
407 generator.setLog( getLog() );
408 generator.setEnableRulesSummary( enableRulesSummary );
409 generator.setEnableSeveritySummary( enableSeveritySummary );
410 generator.setEnableFilesSummary( enableFilesSummary );
411 generator.setEnableRSS( enableRSS );
412 generator.setCheckstyleConfig( results.getConfiguration() );
413 if ( linkXRef )
414 {
415 String relativePath = PathTool.getRelativePath( getOutputDirectory(), xrefLocation.getAbsolutePath() );
416 if ( StringUtils.isEmpty( relativePath ) )
417 {
418 relativePath = ".";
419 }
420 relativePath = relativePath + "/" + xrefLocation.getName();
421 if ( xrefLocation.exists() )
422 {
423
424
425 generator.setXrefLocation( relativePath );
426 }
427 else
428 {
429
430 for ( Iterator<ReportPlugin> reports = getProject().getReportPlugins().iterator(); reports.hasNext(); )
431 {
432 ReportPlugin report = reports.next();
433
434 String artifactId = report.getArtifactId();
435 if ( "maven-jxr-plugin".equals( artifactId ) || "jxr-maven-plugin".equals( artifactId ) )
436 {
437 generator.setXrefLocation( relativePath );
438 }
439 }
440 }
441
442 if ( generator.getXrefLocation() == null )
443 {
444 getLog().warn( "Unable to locate Source XRef to link to - DISABLED" );
445 }
446 }
447 generator.generateReport( results );
448 }
449
450 private static ResourceBundle getBundle( Locale locale )
451 {
452 return ResourceBundle.getBundle( "checkstyle-report", locale, AbstractCheckstyleReport.class.getClassLoader() );
453 }
454
455
456 public void setReportOutputDirectory( File reportOutputDirectory )
457 {
458 super.setReportOutputDirectory( reportOutputDirectory );
459 this.outputDirectory = reportOutputDirectory;
460 }
461 }