1 package org.apache.maven.plugin.checkstyle;
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 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.net.URL;
29 import java.util.Calendar;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.Locale;
34 import java.util.Map;
35 import java.util.ResourceBundle;
36
37 import org.apache.maven.doxia.siterenderer.Renderer;
38 import org.apache.maven.doxia.tools.SiteTool;
39 import org.apache.maven.model.ReportPlugin;
40 import org.apache.maven.plugin.checkstyle.rss.CheckstyleRssGenerator;
41 import org.apache.maven.plugin.checkstyle.rss.CheckstyleRssGeneratorRequest;
42 import org.apache.maven.project.MavenProject;
43 import org.apache.maven.reporting.AbstractMavenReport;
44 import org.apache.maven.reporting.MavenReportException;
45 import org.codehaus.plexus.resource.ResourceManager;
46 import org.codehaus.plexus.resource.loader.FileResourceLoader;
47 import org.codehaus.plexus.util.PathTool;
48 import org.codehaus.plexus.util.StringUtils;
49
50 import com.puppycrawl.tools.checkstyle.DefaultLogger;
51 import com.puppycrawl.tools.checkstyle.XMLLogger;
52 import com.puppycrawl.tools.checkstyle.api.AuditListener;
53 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
54
55 /**
56 * Perform a Checkstyle analysis, and generate a report on violations.
57 *
58 * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
59 * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
60 * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
61 * @version $Id: CheckstyleReport.html 816663 2012-05-08 14:00:13Z hboutemy $
62 * @goal checkstyle
63 * @requiresDependencyResolution compile
64 * @threadSafe
65 */
66 public class CheckstyleReport
67 extends AbstractMavenReport
68 {
69 public static final String PLUGIN_RESOURCES = "org/apache/maven/plugin/checkstyle";
70
71 /**
72 * @deprecated Remove with format parameter.
73 */
74 private static final Map<String, String> FORMAT_TO_CONFIG_LOCATION;
75
76 static
77 {
78 Map<String, String> fmt2Cfg = new HashMap<String, String>();
79
80 fmt2Cfg.put( "sun", "config/sun_checks.xml" );
81 fmt2Cfg.put( "turbine", "config/turbine_checks.xml" );
82 fmt2Cfg.put( "avalon", "config/avalon_checks.xml" );
83 fmt2Cfg.put( "maven", "config/maven_checks.xml" );
84
85 FORMAT_TO_CONFIG_LOCATION = Collections.unmodifiableMap( fmt2Cfg );
86 }
87
88 /**
89 * Skip entire check.
90 *
91 * @parameter expression="${checkstyle.skip}" default-value="false"
92 * @since 2.2
93 */
94 private boolean skip;
95
96 /**
97 * The output directory for the report. Note that this parameter is only
98 * evaluated if the goal is run directly from the command line. If the goal
99 * is run indirectly as part of a site generation, the output directory
100 * configured in Maven Site Plugin is used instead.
101 *
102 * @parameter default-value="${project.reporting.outputDirectory}"
103 * @required
104 */
105 private File outputDirectory;
106
107 /**
108 * Specifies if the Rules summary should be enabled or not.
109 *
110 * @parameter expression="${checkstyle.enable.rules.summary}"
111 * default-value="true"
112 */
113 private boolean enableRulesSummary;
114
115 /**
116 * Specifies if the Severity summary should be enabled or not.
117 *
118 * @parameter expression="${checkstyle.enable.severity.summary}"
119 * default-value="true"
120 */
121 private boolean enableSeveritySummary;
122
123 /**
124 * Specifies if the Files summary should be enabled or not.
125 *
126 * @parameter expression="${checkstyle.enable.files.summary}"
127 * default-value="true"
128 */
129 private boolean enableFilesSummary;
130
131 /**
132 * Specifies if the RSS should be enabled or not.
133 *
134 * @parameter expression="${checkstyle.enable.rss}" default-value="true"
135 */
136 private boolean enableRSS;
137
138 /**
139 * Specifies the names filter of the source files to be used for Checkstyle.
140 *
141 * @parameter expression="${checkstyle.includes}" default-value="**\/*.java"
142 * @required
143 */
144 private String includes;
145
146 /**
147 * Specifies the names filter of the source files to be excluded for
148 * Checkstyle.
149 *
150 * @parameter expression="${checkstyle.excludes}"
151 */
152 private String excludes;
153
154 /**
155 * <p>
156 * Specifies the location of the XML configuration to use.
157 * </p>
158 *
159 * <p>
160 * Potential values are a filesystem path, a URL, or a classpath resource.
161 * This parameter expects that the contents of the location conform to the
162 * xml format (Checkstyle <a
163 * href="http://checkstyle.sourceforge.net/config.html#Modules">Checker
164 * module</a>) configuration of rulesets.
165 * </p>
166 *
167 * <p>
168 * This parameter is resolved as resource, URL, then file. If successfully
169 * resolved, the contents of the configuration is copied into the
170 * <code>${project.build.directory}/checkstyle-configuration.xml</code>
171 * file before being passed to Checkstyle as a configuration.
172 * </p>
173 *
174 * <p>
175 * There are 4 predefined rulesets.
176 * </p>
177 *
178 * <ul>
179 * <li><code>config/sun_checks.xml</code>: Sun Checks.</li>
180 * <li><code>config/turbine_checks.xml</code>: Turbine Checks.</li>
181 * <li><code>config/avalon_checks.xml</code>: Avalon Checks.</li>
182 * <li><code>config/maven_checks.xml</code>: Maven Source Checks.</li>
183 * </ul>
184 *
185 * @parameter expression="${checkstyle.config.location}"
186 * default-value="config/sun_checks.xml"
187 */
188 private String configLocation;
189
190 /**
191 * Specifies what predefined check set to use. Available sets are "sun" (for
192 * the Sun coding conventions), "turbine", and "avalon".
193 *
194 * @parameter default-value="sun"
195 * @deprecated Use configLocation instead.
196 */
197 private String format;
198
199 /**
200 * <p>
201 * Specifies the location of the properties file.
202 * </p>
203 *
204 * <p>
205 * This parameter is resolved as URL, File then resource. If successfully
206 * resolved, the contents of the properties location is copied into the
207 * <code>${project.build.directory}/checkstyle-checker.properties</code>
208 * file before being passed to Checkstyle for loading.
209 * </p>
210 *
211 * <p>
212 * The contents of the <code>propertiesLocation</code> will be made
213 * available to Checkstyle for specifying values for parameters within the
214 * xml configuration (specified in the <code>configLocation</code>
215 * parameter).
216 * </p>
217 *
218 * @parameter expression="${checkstyle.properties.location}"
219 * @since 2.0-beta-2
220 */
221 private String propertiesLocation;
222
223 /**
224 * Specifies the location of the Checkstyle properties file that will be used to
225 * check the source.
226 *
227 * @parameter
228 * @deprecated Use propertiesLocation instead.
229 */
230 private File propertiesFile;
231
232 /**
233 * Specifies the URL of the Checkstyle properties that will be used to check
234 * the source.
235 *
236 * @parameter
237 * @deprecated Use propertiesLocation instead.
238 */
239 private URL propertiesURL;
240
241 /**
242 * Allows for specifying raw property expansion information.
243 *
244 * @parameter
245 */
246 private String propertyExpansion;
247
248 /**
249 * <p>
250 * Specifies the location of the License file (a.k.a. the header file) that
251 * can be used by Checkstyle to verify that source code has the correct
252 * license header.
253 * </p>
254 * <p>
255 * You need to use ${checkstyle.header.file} in your Checkstyle xml
256 * configuration to reference the name of this header file.
257 * </p>
258 * <p>
259 * For instance:
260 * </p>
261 * <p>
262 * <code>
263 * <module name="RegexpHeader">
264 * <property name="headerFile" value="${checkstyle.header.file}"/>
265 * </module>
266 * </code>
267 * </p>
268 *
269 * @parameter expression="${checkstyle.header.file}" default-value="LICENSE.txt"
270 * @since 2.0-beta-2
271 */
272 private String headerLocation;
273
274 /**
275 * Specifies the location of the License file (a.k.a. the header file) that
276 * is used by Checkstyle to verify that source code has the correct
277 * license header.
278 *
279 * @parameter expression="${basedir}/LICENSE.txt"
280 * @deprecated Use headerLocation instead.
281 */
282 private File headerFile;
283
284 /**
285 * Specifies the cache file used to speed up Checkstyle on successive runs.
286 *
287 * @parameter default-value="${project.build.directory}/checkstyle-cachefile"
288 */
289 private String cacheFile;
290
291 /**
292 * If <code>null</code>, the Checkstyle plugin will display violations on stdout.
293 * Otherwise, a text file will be created with the violations.
294 *
295 * @parameter
296 */
297 private File useFile;
298
299 /**
300 * SiteTool.
301 *
302 * @since 2.2
303 * @component role="org.apache.maven.doxia.tools.SiteTool"
304 * @required
305 * @readonly
306 */
307 protected SiteTool siteTool;
308
309 /**
310 * <p>
311 * Specifies the location of the suppressions XML file to use.
312 * </p>
313 *
314 * <p>
315 * This parameter is resolved as resource, URL, then file. If successfully
316 * resolved, the contents of the suppressions XML is copied into the
317 * <code>${project.build.directory}/checkstyle-supressions.xml</code> file
318 * before being passed to Checkstyle for loading.
319 * </p>
320 *
321 * <p>
322 * See <code>suppressionsFileExpression</code> for the property that will
323 * be made available to your checkstyle configuration.
324 * </p>
325 *
326 * @parameter expression="${checkstyle.suppressions.location}"
327 * @since 2.0-beta-2
328 */
329 private String suppressionsLocation;
330
331 /**
332 * The key to be used in the properties for the suppressions file.
333 *
334 * @parameter expression="${checkstyle.suppression.expression}"
335 * default-value="checkstyle.suppressions.file"
336 * @since 2.1
337 */
338 private String suppressionsFileExpression;
339
340 /**
341 * Specifies the location of the suppressions XML file to use. The plugin
342 * defines a Checkstyle property named
343 * <code>checkstyle.suppressions.file</code> with the value of this
344 * property. This allows using the Checkstyle property in your own custom
345 * checkstyle configuration file when specifying a suppressions file.
346 *
347 * @parameter
348 * @deprecated Use suppressionsLocation instead.
349 */
350 private String suppressionsFile;
351
352 /**
353 * Specifies the path and filename to save the checkstyle output. The format
354 * of the output file is determined by the <code>outputFileFormat</code>
355 * parameter.
356 *
357 * @parameter expression="${checkstyle.output.file}"
358 * default-value="${project.build.directory}/checkstyle-result.xml"
359 */
360 private File outputFile;
361
362 /**
363 * Specifies the format of the output to be used when writing to the output
364 * file. Valid values are "plain" and "xml".
365 *
366 * @parameter expression="${checkstyle.output.format}" default-value="xml"
367 */
368 private String outputFileFormat;
369
370 /**
371 * <p>
372 * Specifies the location of the package names XML to be used to configure
373 * the Checkstyle <a
374 * href="http://checkstyle.sourceforge.net/config.html#Packages">Packages</a>.
375 * </p>
376 *
377 * <p>
378 * This parameter is resolved as resource, URL, then file. If resolved to a
379 * resource, or a URL, the contents of the package names XML is copied into
380 * the <code>${project.build.directory}/checkstyle-packagenames.xml</code>
381 * file before being passed to Checkstyle for loading.
382 * </p>
383 *
384 * @parameter
385 * @since 2.0-beta-2
386 */
387 private String packageNamesLocation;
388
389 /**
390 * Specifies the location of the package names XML to be used to configure
391 * Checkstyle.
392 *
393 * @parameter
394 * @deprecated Use packageNamesLocation instead.
395 */
396 private String packageNamesFile;
397
398 /**
399 * Specifies if the build should fail upon a violation.
400 *
401 * @parameter default-value="false"
402 */
403 private boolean failsOnError;
404
405 /**
406 * Specifies the location of the source directory to be used for Checkstyle.
407 *
408 * @parameter default-value="${project.build.sourceDirectory}"
409 * @required
410 */
411 private File sourceDirectory;
412
413 /**
414 * Specifies the location of the test source directory to be used for
415 * Checkstyle.
416 *
417 * @parameter default-value="${project.build.testSourceDirectory}"
418 * @since 2.2
419 */
420 private File testSourceDirectory;
421
422 /**
423 * Include or not the test source directory to be used for Checkstyle.
424 *
425 * @parameter default-value="${false}"
426 * @since 2.2
427 */
428 private boolean includeTestSourceDirectory;
429
430 /**
431 * The Maven Project Object.
432 *
433 * @parameter default-value="${project}"
434 * @required
435 * @readonly
436 */
437 private MavenProject project;
438
439 /**
440 * Output errors to console.
441 *
442 * @parameter default-value="false"
443 */
444 private boolean consoleOutput;
445
446 /**
447 * Link the violation line numbers to the source xref. Will link
448 * automatically if Maven JXR plugin is being used.
449 *
450 * @parameter expression="${linkXRef}" default-value="true"
451 * @since 2.1
452 */
453 private boolean linkXRef;
454
455 /**
456 * Location of the Xrefs to link to.
457 *
458 * @parameter default-value="${project.reporting.outputDirectory}/xref"
459 */
460 private File xrefLocation;
461
462 /**
463 * The file encoding to use when reading the source files. If the property <code>project.build.sourceEncoding</code>
464 * is not set, the platform default encoding is used. <strong>Note:</strong> This parameter always overrides the
465 * property <code>charset</code> from Checkstyle's <code>TreeWalker</code> module.
466 *
467 * @parameter expression="${encoding}" default-value="${project.build.sourceEncoding}"
468 * @since 2.2
469 */
470 private String encoding;
471
472 /**
473 * @component
474 * @required
475 * @readonly
476 */
477 private Renderer siteRenderer;
478
479 private ByteArrayOutputStream stringOutputStream;
480
481 /**
482 * @component
483 * @required
484 * @readonly
485 */
486 private ResourceManager locator;
487
488 /**
489 * CheckstyleRssGenerator.
490 *
491 * @since 2.4
492 * @component role="org.apache.maven.plugin.checkstyle.rss.CheckstyleRssGenerator" role-hint="default"
493 * @required
494 * @readonly
495 */
496 protected CheckstyleRssGenerator checkstyleRssGenerator;
497
498 /**
499 * @since 2.5
500 * @component role="org.apache.maven.plugin.checkstyle.CheckstyleExecutor" role-hint="default"
501 * @required
502 * @readonly
503 */
504 protected CheckstyleExecutor checkstyleExecutor;
505
506
507 /** {@inheritDoc} */
508 public String getName( Locale locale )
509 {
510 return getBundle( locale ).getString( "report.checkstyle.name" );
511 }
512
513 /** {@inheritDoc} */
514 public String getDescription( Locale locale )
515 {
516 return getBundle( locale ).getString( "report.checkstyle.description" );
517 }
518
519 /** {@inheritDoc} */
520 protected String getOutputDirectory()
521 {
522 return outputDirectory.getAbsolutePath();
523 }
524
525 /** {@inheritDoc} */
526 protected MavenProject getProject()
527 {
528 return project;
529 }
530
531 /** {@inheritDoc} */
532 protected Renderer getSiteRenderer()
533 {
534 return siteRenderer;
535 }
536
537 /** {@inheritDoc} */
538 public void executeReport( Locale locale )
539 throws MavenReportException
540 {
541 if ( !skip )
542 {
543 mergeDeprecatedInfo();
544
545 locator.addSearchPath( FileResourceLoader.ID, project.getFile().getParentFile().getAbsolutePath() );
546 locator.addSearchPath( "url", "" );
547
548 locator.setOutputDirectory( new File( project.getBuild().getDirectory() ) );
549
550 if ( !canGenerateReport() )
551 {
552 getLog().info( "Source directory does not exist - skipping report." );
553 return;
554 }
555
556 // for when we start using maven-shared-io and
557 // maven-shared-monitor...
558 // locator = new Locator( new MojoLogMonitorAdaptor( getLog() ) );
559
560 // locator = new Locator( getLog(), new File(
561 // project.getBuild().getDirectory() ) );
562
563 ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
564
565 try
566 {
567 CheckstyleExecutorRequest request = new CheckstyleExecutorRequest();
568 request.setConsoleListener( getConsoleListener() ).setConsoleOutput( consoleOutput )
569 .setExcludes( excludes ).setFailsOnError( failsOnError ).setIncludes( includes )
570 .setIncludeTestSourceDirectory( includeTestSourceDirectory ).setListener( getListener() )
571 .setLog( getLog() ).setProject( project ).setSourceDirectory( sourceDirectory )
572 .setStringOutputStream( stringOutputStream ).setSuppressionsLocation( suppressionsLocation )
573 .setTestSourceDirectory( testSourceDirectory ).setConfigLocation( configLocation )
574 .setPropertyExpansion( propertyExpansion ).setHeaderLocation( headerLocation )
575 .setCacheFile( cacheFile ).setSuppressionsFileExpression( suppressionsFileExpression )
576 .setEncoding( encoding ).setPropertiesLocation( propertiesLocation );
577
578 CheckstyleResults results = checkstyleExecutor.executeCheckstyle( request );
579
580 ResourceBundle bundle = getBundle( locale );
581 generateReportStatics();
582 generateMainReport( results, bundle );
583 if ( enableRSS )
584 {
585 CheckstyleRssGeneratorRequest checkstyleRssGeneratorRequest =
586 new CheckstyleRssGeneratorRequest( this.project, this.getCopyright(), outputDirectory, getLog() );
587 checkstyleRssGenerator.generateRSS( results, checkstyleRssGeneratorRequest );
588 }
589
590 }
591 catch ( CheckstyleException e )
592 {
593 throw new MavenReportException( "Failed during checkstyle configuration", e );
594 }
595 catch ( CheckstyleExecutorException e )
596 {
597 throw new MavenReportException( "Failed during checkstyle execution", e );
598 }
599 finally
600 {
601 //be sure to restore original context classloader
602 Thread.currentThread().setContextClassLoader( currentClassLoader );
603 }
604 }
605 }
606
607 private void generateReportStatics()
608 throws MavenReportException
609 {
610 ReportResource rresource = new ReportResource( PLUGIN_RESOURCES, outputDirectory );
611 try
612 {
613 rresource.copy( "images/rss.png" );
614 }
615 catch ( IOException e )
616 {
617 throw new MavenReportException( "Unable to copy static resources.", e );
618 }
619 }
620
621
622 private String getCopyright()
623 {
624 String copyright;
625 int currentYear = Calendar.getInstance().get( Calendar.YEAR );
626 if ( StringUtils.isNotEmpty( project.getInceptionYear() )
627 && !String.valueOf( currentYear ).equals( project.getInceptionYear() ) )
628 {
629 copyright = project.getInceptionYear() + " - " + currentYear;
630 }
631 else
632 {
633 copyright = String.valueOf( currentYear );
634 }
635
636 if ( ( project.getOrganization() != null ) && StringUtils.isNotEmpty( project.getOrganization().getName() ) )
637 {
638 copyright = copyright + " " + project.getOrganization().getName();
639 }
640 return copyright;
641 }
642
643 private void generateMainReport( CheckstyleResults results, ResourceBundle bundle )
644 {
645 CheckstyleReportGenerator generator =
646 new CheckstyleReportGenerator( getSink(), bundle, project.getBasedir(), siteTool );
647
648 generator.setLog( getLog() );
649 generator.setEnableRulesSummary( enableRulesSummary );
650 generator.setEnableSeveritySummary( enableSeveritySummary );
651 generator.setEnableFilesSummary( enableFilesSummary );
652 generator.setEnableRSS( enableRSS );
653 generator.setCheckstyleConfig( results.getConfiguration() );
654 if ( linkXRef )
655 {
656 String relativePath = PathTool.getRelativePath( getOutputDirectory(), xrefLocation.getAbsolutePath() );
657 if ( StringUtils.isEmpty( relativePath ) )
658 {
659 relativePath = ".";
660 }
661 relativePath = relativePath + "/" + xrefLocation.getName();
662 if ( xrefLocation.exists() )
663 {
664 // XRef was already generated by manual execution of a lifecycle
665 // binding
666 generator.setXrefLocation( relativePath );
667 }
668 else
669 {
670 // Not yet generated - check if the report is on its way
671 for ( Iterator<ReportPlugin> reports = getProject().getReportPlugins().iterator(); reports.hasNext(); )
672 {
673 ReportPlugin report = reports.next();
674
675 String artifactId = report.getArtifactId();
676 if ( "maven-jxr-plugin".equals( artifactId ) || "jxr-maven-plugin".equals( artifactId ) )
677 {
678 generator.setXrefLocation( relativePath );
679 }
680 }
681 }
682
683 if ( generator.getXrefLocation() == null )
684 {
685 getLog().warn( "Unable to locate Source XRef to link to - DISABLED" );
686 }
687 }
688 generator.generateReport( results );
689 }
690
691 /**
692 * Merge in the deprecated parameters to the new ones, unless the new
693 * parameters have values.
694 *
695 * @deprecated Remove when deprecated params are removed.
696 */
697 private void mergeDeprecatedInfo()
698 {
699 if ( "config/sun_checks.xml".equals( configLocation ) && !"sun".equals( format ) )
700 {
701 configLocation = (String) FORMAT_TO_CONFIG_LOCATION.get( format );
702 }
703
704 if ( StringUtils.isEmpty( propertiesLocation ) )
705 {
706 if ( propertiesFile != null )
707 {
708 propertiesLocation = propertiesFile.getPath();
709 }
710 else if ( propertiesURL != null )
711 {
712 propertiesLocation = propertiesURL.toExternalForm();
713 }
714 }
715
716 if ( "LICENSE.txt".equals( headerLocation ) )
717 {
718 File defaultHeaderFile = new File( project.getBasedir(), "LICENSE.txt" );
719 if ( !defaultHeaderFile.equals( headerFile ) )
720 {
721 headerLocation = headerFile.getPath();
722 }
723 }
724
725 if ( StringUtils.isEmpty( suppressionsLocation ) )
726 {
727 suppressionsLocation = suppressionsFile;
728 }
729
730 if ( StringUtils.isEmpty( packageNamesLocation ) )
731 {
732 packageNamesLocation = packageNamesFile;
733 }
734 }
735
736
737 /** {@inheritDoc} */
738 public String getOutputName()
739 {
740 return "checkstyle";
741 }
742
743 private AuditListener getListener()
744 throws MavenReportException
745 {
746 AuditListener listener = null;
747
748 if ( StringUtils.isNotEmpty( outputFileFormat ) )
749 {
750 File resultFile = outputFile;
751
752 OutputStream out = getOutputStream( resultFile );
753
754 if ( "xml".equals( outputFileFormat ) )
755 {
756 listener = new XMLLogger( out, true );
757 }
758 else if ( "plain".equals( outputFileFormat ) )
759 {
760 listener = new DefaultLogger( out, true );
761 }
762 else
763 {
764 // TODO: failure if not a report
765 throw new MavenReportException( "Invalid output file format: (" + outputFileFormat
766 + "). Must be 'plain' or 'xml'." );
767 }
768 }
769
770 return listener;
771 }
772
773 private OutputStream getOutputStream( File file )
774 throws MavenReportException
775 {
776 File parentFile = file.getAbsoluteFile().getParentFile();
777
778 if ( !parentFile.exists() )
779 {
780 parentFile.mkdirs();
781 }
782
783 FileOutputStream fileOutputStream;
784 try
785 {
786 fileOutputStream = new FileOutputStream( file );
787 }
788 catch ( FileNotFoundException e )
789 {
790 throw new MavenReportException( "Unable to create output stream: " + file, e );
791 }
792 return fileOutputStream;
793 }
794
795 private DefaultLogger getConsoleListener()
796 throws MavenReportException
797 {
798 DefaultLogger consoleListener;
799
800 if ( useFile == null )
801 {
802 stringOutputStream = new ByteArrayOutputStream();
803 consoleListener = new DefaultLogger( stringOutputStream, false );
804 }
805 else
806 {
807 OutputStream out = getOutputStream( useFile );
808
809 consoleListener = new DefaultLogger( out, true );
810 }
811
812 return consoleListener;
813 }
814
815 private static ResourceBundle getBundle( Locale locale )
816 {
817 return ResourceBundle.getBundle( "checkstyle-report", locale, CheckstyleReport.class.getClassLoader() );
818 }
819
820 /** {@inheritDoc} */
821 public boolean canGenerateReport()
822 {
823 // TODO: would be good to scan the files here
824 return sourceDirectory.exists() || ( includeTestSourceDirectory && testSourceDirectory.exists() );
825 }
826
827 /** {@inheritDoc} */
828 public void setReportOutputDirectory( File reportOutputDirectory )
829 {
830 super.setReportOutputDirectory( reportOutputDirectory );
831 this.outputDirectory = reportOutputDirectory;
832 }
833 }