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