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 java.io.ByteArrayOutputStream;
23 import java.io.File;
24 import java.io.FileNotFoundException;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.OutputStream;
28 import java.util.ArrayList;
29 import java.util.Calendar;
30 import java.util.List;
31 import java.util.Locale;
32 import java.util.ResourceBundle;
33
34 import org.apache.maven.artifact.Artifact;
35 import org.apache.maven.doxia.siterenderer.Renderer;
36 import org.apache.maven.doxia.tools.SiteTool;
37 import org.apache.maven.model.Dependency;
38 import org.apache.maven.model.Plugin;
39 import org.apache.maven.model.ReportPlugin;
40 import org.apache.maven.model.Resource;
41 import org.apache.maven.plugin.checkstyle.rss.CheckstyleRssGenerator;
42 import org.apache.maven.plugin.checkstyle.rss.CheckstyleRssGeneratorRequest;
43 import org.apache.maven.plugin.descriptor.PluginDescriptor;
44 import org.apache.maven.plugins.annotations.Component;
45 import org.apache.maven.plugins.annotations.Parameter;
46 import org.apache.maven.project.MavenProject;
47 import org.apache.maven.reporting.AbstractMavenReport;
48 import org.apache.maven.reporting.MavenReportException;
49 import org.codehaus.plexus.resource.ResourceManager;
50 import org.codehaus.plexus.resource.loader.FileResourceLoader;
51 import org.codehaus.plexus.util.PathTool;
52 import org.codehaus.plexus.util.StringUtils;
53
54 import com.puppycrawl.tools.checkstyle.DefaultLogger;
55 import com.puppycrawl.tools.checkstyle.XMLLogger;
56 import com.puppycrawl.tools.checkstyle.api.AuditListener;
57 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
58
59
60
61
62
63
64
65 public abstract class AbstractCheckstyleReport
66 extends AbstractMavenReport
67 {
68 public static final String PLUGIN_RESOURCES = "org/apache/maven/plugin/checkstyle";
69
70 protected static final String JAVA_FILES = "**\\/*.java";
71
72
73
74
75 @Parameter( defaultValue = "${project.build.directory}/checkstyle-cachefile" )
76 protected String cacheFile;
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 @Parameter( property = "checkstyle.config.location", defaultValue = "config/sun_checks.xml" )
110 protected String configLocation;
111
112
113
114
115 @Parameter( property = "checkstyle.consoleOutput", defaultValue = "false" )
116 protected boolean consoleOutput;
117
118
119
120
121
122
123
124
125 @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
126 protected String encoding;
127
128
129
130
131 @Parameter( defaultValue = "false" )
132 protected boolean failsOnError;
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 @Parameter( property = "checkstyle.header.file", defaultValue = "LICENSE.txt" )
158 protected String headerLocation;
159
160
161
162
163
164
165 @Parameter( property = "checkstyle.skip", defaultValue = "false" )
166 protected boolean skip;
167
168
169
170
171
172
173
174 @Parameter( defaultValue = "${project.reporting.outputDirectory}", required = true )
175 private File outputDirectory;
176
177
178
179
180
181
182 @Parameter( property = "checkstyle.output.file", defaultValue = "${project.build.directory}/checkstyle-result.xml" )
183 private File outputFile;
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206 @Parameter( property = "checkstyle.properties.location" )
207 protected String propertiesLocation;
208
209
210
211
212 @Parameter
213 protected String propertyExpansion;
214
215
216
217
218
219
220 @Parameter( defaultValue = "${project.resources}", readonly = true )
221 protected List<Resource> resources;
222
223
224
225
226
227
228 @Parameter( defaultValue = "${project.testResources}", readonly = true )
229 protected List<Resource> testResources;
230
231
232
233
234 @Parameter( property = "checkstyle.includes", defaultValue = JAVA_FILES, required = true )
235 protected String includes;
236
237
238
239
240
241 @Parameter( property = "checkstyle.excludes" )
242 protected String excludes;
243
244
245
246
247
248 @Parameter( property = "checkstyle.resourceIncludes", defaultValue = "**/*.properties", required = true )
249 protected String resourceIncludes;
250
251
252
253
254
255
256 @Parameter( property = "checkstyle.resourceExcludes" )
257 protected String resourceExcludes;
258
259
260
261
262
263 @Parameter( property = "checkstyle.includeResources", defaultValue = "true", required = true )
264 protected boolean includeResources;
265
266
267
268
269
270 @Parameter( property = "checkstyle.includeTestResources", defaultValue = "true", required = true )
271 protected boolean includeTestResources;
272
273
274
275
276 @Parameter( defaultValue = "${project.build.sourceDirectory}", required = true )
277 protected File sourceDirectory;
278
279
280
281
282
283
284
285 @Parameter( defaultValue = "${project.build.testSourceDirectory}" )
286 protected File testSourceDirectory;
287
288
289
290
291
292
293 @Parameter( defaultValue = "false" )
294 protected boolean includeTestSourceDirectory;
295
296
297
298
299
300
301 @Parameter( property = "checkstyle.suppression.expression", defaultValue = "checkstyle.suppressions.file" )
302 protected String suppressionsFileExpression;
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323 @Parameter( property = "checkstyle.suppressions.location" )
324 protected String suppressionsLocation;
325
326
327
328
329
330 @Parameter
331 private File useFile;
332
333
334
335
336
337 @Parameter( property = "checkstyle.output.format", defaultValue = "xml" )
338 private String outputFileFormat;
339
340
341
342
343 @Parameter( property = "checkstyle.enable.rules.summary", defaultValue = "true" )
344 private boolean enableRulesSummary;
345
346
347
348
349 @Parameter( property = "checkstyle.enable.severity.summary", defaultValue = "true" )
350 private boolean enableSeveritySummary;
351
352
353
354
355 @Parameter( property = "checkstyle.enable.files.summary", defaultValue = "true" )
356 private boolean enableFilesSummary;
357
358
359
360
361 @Parameter( property = "checkstyle.enable.rss", defaultValue = "true" )
362 private boolean enableRSS;
363
364
365
366
367
368
369 @Component( role = SiteTool.class )
370 protected SiteTool siteTool;
371
372
373
374
375 @Parameter( defaultValue = "${project}" )
376 protected MavenProject project;
377
378
379
380
381
382 @Parameter( defaultValue= "${plugin}" )
383 private PluginDescriptor plugin;
384
385
386
387
388
389
390
391 @Parameter( property = "linkXRef", defaultValue = "true" )
392 private boolean linkXRef;
393
394
395
396
397 @Parameter( defaultValue = "${project.reporting.outputDirectory}/xref" )
398 private File xrefLocation;
399
400
401
402
403
404
405
406 @Parameter
407 private List<String> treeWalkerNames;
408
409
410
411 @Component
412 private Renderer siteRenderer;
413
414
415
416 @Component
417 protected ResourceManager locator;
418
419
420
421
422
423
424 @Component( role = CheckstyleRssGenerator.class, hint = "default" )
425 protected CheckstyleRssGenerator checkstyleRssGenerator;
426
427
428
429
430 @Component( role = CheckstyleExecutor.class, hint = "default" )
431 protected CheckstyleExecutor checkstyleExecutor;
432
433 protected ByteArrayOutputStream stringOutputStream;
434
435
436 public String getName( Locale locale )
437 {
438 return getBundle( locale ).getString( "report.checkstyle.name" );
439 }
440
441
442 public String getDescription( Locale locale )
443 {
444 return getBundle( locale ).getString( "report.checkstyle.description" );
445 }
446
447
448 protected String getOutputDirectory()
449 {
450 return outputDirectory.getAbsolutePath();
451 }
452
453
454 protected MavenProject getProject()
455 {
456 return project;
457 }
458
459
460 protected Renderer getSiteRenderer()
461 {
462 return siteRenderer;
463 }
464
465
466 public void executeReport( Locale locale )
467 throws MavenReportException
468 {
469 locator.addSearchPath( FileResourceLoader.ID, project.getFile().getParentFile().getAbsolutePath() );
470 locator.addSearchPath( "url", "" );
471
472 locator.setOutputDirectory( new File( project.getBuild().getDirectory() ) );
473
474
475
476
477
478
479
480
481 ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
482
483 try
484 {
485 CheckstyleExecutorRequest request = createRequest().setLicenseArtifacts( collectArtifacts( "license" ) )
486 .setConfigurationArtifacts( collectArtifacts( "configuration" ) );
487
488 CheckstyleResults results = checkstyleExecutor.executeCheckstyle( request );
489
490 ResourceBundle bundle = getBundle( locale );
491 generateReportStatics();
492 generateMainReport( results, bundle );
493 if ( enableRSS )
494 {
495 CheckstyleRssGeneratorRequest checkstyleRssGeneratorRequest =
496 new CheckstyleRssGeneratorRequest( this.project, this.getCopyright(), outputDirectory, getLog() );
497 checkstyleRssGenerator.generateRSS( results, checkstyleRssGeneratorRequest );
498 }
499
500 }
501 catch ( CheckstyleException e )
502 {
503 throw new MavenReportException( "Failed during checkstyle configuration", e );
504 }
505 catch ( CheckstyleExecutorException e )
506 {
507 throw new MavenReportException( "Failed during checkstyle execution", e );
508 }
509 finally
510 {
511
512 Thread.currentThread().setContextClassLoader( currentClassLoader );
513 }
514 }
515
516
517
518
519
520
521
522 protected abstract CheckstyleExecutorRequest createRequest()
523 throws MavenReportException;
524
525 private List<Artifact> collectArtifacts( String hint )
526 {
527 List<Artifact> artifacts = new ArrayList<Artifact>();
528
529 Plugin checkstylePlugin =
530 (Plugin) project.getBuild().getPluginsAsMap().get( plugin.getGroupId() + ":" + plugin.getArtifactId() );
531 if ( checkstylePlugin != null )
532 {
533 for ( Dependency dep : checkstylePlugin.getDependencies() )
534 {
535
536 String depKey = dep.getGroupId() + ":" + dep.getArtifactId();
537 artifacts.add( (Artifact) plugin.getArtifactMap().get( depKey ) );
538 }
539 }
540
541 return artifacts;
542 }
543
544
545
546
547
548
549
550 protected AuditListener getListener()
551 throws MavenReportException
552 {
553 AuditListener listener = null;
554
555 if ( StringUtils.isNotEmpty( outputFileFormat ) )
556 {
557 File resultFile = outputFile;
558
559 OutputStream out = getOutputStream( resultFile );
560
561 if ( "xml".equals( outputFileFormat ) )
562 {
563 listener = new XMLLogger( out, true );
564 }
565 else if ( "plain".equals( outputFileFormat ) )
566 {
567 listener = new DefaultLogger( out, true );
568 }
569 else
570 {
571
572 throw new MavenReportException( "Invalid output file format: (" + outputFileFormat
573 + "). Must be 'plain' or 'xml'." );
574 }
575 }
576
577 return listener;
578 }
579
580 private OutputStream getOutputStream( File file )
581 throws MavenReportException
582 {
583 File parentFile = file.getAbsoluteFile().getParentFile();
584
585 if ( !parentFile.exists() )
586 {
587 parentFile.mkdirs();
588 }
589
590 FileOutputStream fileOutputStream;
591 try
592 {
593 fileOutputStream = new FileOutputStream( file );
594 }
595 catch ( FileNotFoundException e )
596 {
597 throw new MavenReportException( "Unable to create output stream: " + file, e );
598 }
599 return fileOutputStream;
600 }
601
602
603
604
605
606
607
608 protected DefaultLogger getConsoleListener()
609 throws MavenReportException
610 {
611 DefaultLogger consoleListener;
612
613 if ( useFile == null )
614 {
615 stringOutputStream = new ByteArrayOutputStream();
616 consoleListener = new DefaultLogger( stringOutputStream, false );
617 }
618 else
619 {
620 OutputStream out = getOutputStream( useFile );
621
622 consoleListener = new DefaultLogger( out, true );
623 }
624
625 return consoleListener;
626 }
627
628 private void generateReportStatics()
629 throws MavenReportException
630 {
631 ReportResource rresource = new ReportResource( PLUGIN_RESOURCES, outputDirectory );
632 try
633 {
634 rresource.copy( "images/rss.png" );
635 }
636 catch ( IOException e )
637 {
638 throw new MavenReportException( "Unable to copy static resources.", e );
639 }
640 }
641
642
643 private String getCopyright()
644 {
645 String copyright;
646 int currentYear = Calendar.getInstance().get( Calendar.YEAR );
647 if ( StringUtils.isNotEmpty( project.getInceptionYear() )
648 && !String.valueOf( currentYear ).equals( project.getInceptionYear() ) )
649 {
650 copyright = project.getInceptionYear() + " - " + currentYear;
651 }
652 else
653 {
654 copyright = String.valueOf( currentYear );
655 }
656
657 if ( ( project.getOrganization() != null ) && StringUtils.isNotEmpty( project.getOrganization().getName() ) )
658 {
659 copyright = copyright + " " + project.getOrganization().getName();
660 }
661 return copyright;
662 }
663
664 private void generateMainReport( CheckstyleResults results, ResourceBundle bundle )
665 {
666 CheckstyleReportGenerator generator =
667 new CheckstyleReportGenerator( getSink(), bundle, project.getBasedir(), siteTool );
668
669 generator.setLog( getLog() );
670 generator.setEnableRulesSummary( enableRulesSummary );
671 generator.setEnableSeveritySummary( enableSeveritySummary );
672 generator.setEnableFilesSummary( enableFilesSummary );
673 generator.setEnableRSS( enableRSS );
674 generator.setCheckstyleConfig( results.getConfiguration() );
675 if ( linkXRef )
676 {
677 String relativePath = PathTool.getRelativePath( getOutputDirectory(), xrefLocation.getAbsolutePath() );
678 if ( StringUtils.isEmpty( relativePath ) )
679 {
680 relativePath = ".";
681 }
682 relativePath = relativePath + "/" + xrefLocation.getName();
683 if ( xrefLocation.exists() )
684 {
685
686
687 generator.setXrefLocation( relativePath );
688 }
689 else
690 {
691
692 for ( ReportPlugin report : (Iterable<ReportPlugin>) getProject().getReportPlugins() )
693 {
694 String artifactId = report.getArtifactId();
695 if ( "maven-jxr-plugin".equals( artifactId ) || "jxr-maven-plugin".equals( artifactId ) )
696 {
697 generator.setXrefLocation( relativePath );
698 }
699 }
700 }
701
702 if ( generator.getXrefLocation() == null && results.getFileCount() > 0 )
703 {
704 getLog().warn( "Unable to locate Source XRef to link to - DISABLED" );
705 }
706 }
707 if ( treeWalkerNames != null )
708 {
709 generator.setTreeWalkerNames( treeWalkerNames );
710 }
711 generator.generateReport( results );
712 }
713
714 private static ResourceBundle getBundle( Locale locale )
715 {
716 return ResourceBundle.getBundle( "checkstyle-report", locale, AbstractCheckstyleReport.class.getClassLoader() );
717 }
718
719
720 public void setReportOutputDirectory( File reportOutputDirectory )
721 {
722 super.setReportOutputDirectory( reportOutputDirectory );
723 this.outputDirectory = reportOutputDirectory;
724 }
725
726
727 }