View Javadoc
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.BufferedReader;
23  import java.io.ByteArrayOutputStream;
24  import java.io.File;
25  import java.io.FileNotFoundException;
26  import java.io.FileOutputStream;
27  import java.io.IOException;
28  import java.io.OutputStream;
29  import java.io.Reader;
30  import java.util.ArrayList;
31  import java.util.Collections;
32  import java.util.List;
33  import java.util.Map;
34  
35  import org.apache.maven.artifact.Artifact;
36  import org.apache.maven.model.Dependency;
37  import org.apache.maven.model.Plugin;
38  import org.apache.maven.model.PluginManagement;
39  import org.apache.maven.model.Resource;
40  import org.apache.maven.plugin.AbstractMojo;
41  import org.apache.maven.plugin.MojoExecution;
42  import org.apache.maven.plugin.MojoExecutionException;
43  import org.apache.maven.plugin.MojoFailureException;
44  import org.apache.maven.plugin.checkstyle.exec.CheckstyleExecutor;
45  import org.apache.maven.plugin.checkstyle.exec.CheckstyleExecutorException;
46  import org.apache.maven.plugin.checkstyle.exec.CheckstyleExecutorRequest;
47  import org.apache.maven.plugin.descriptor.PluginDescriptor;
48  import org.apache.maven.plugins.annotations.Component;
49  import org.apache.maven.plugins.annotations.LifecyclePhase;
50  import org.apache.maven.plugins.annotations.Mojo;
51  import org.apache.maven.plugins.annotations.Parameter;
52  import org.apache.maven.plugins.annotations.ResolutionScope;
53  import org.apache.maven.project.MavenProject;
54  import org.codehaus.plexus.configuration.PlexusConfiguration;
55  import org.codehaus.plexus.util.FileUtils;
56  import org.codehaus.plexus.util.IOUtil;
57  import org.codehaus.plexus.util.PathTool;
58  import org.codehaus.plexus.util.ReaderFactory;
59  import org.codehaus.plexus.util.StringUtils;
60  import org.codehaus.plexus.util.xml.pull.MXParser;
61  import org.codehaus.plexus.util.xml.pull.XmlPullParser;
62  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
63  
64  import com.puppycrawl.tools.checkstyle.DefaultLogger;
65  import com.puppycrawl.tools.checkstyle.XMLLogger;
66  import com.puppycrawl.tools.checkstyle.api.AuditListener;
67  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
68  
69  /**
70   * Performs Checkstyle analysis and outputs violations or a count of violations
71   * to the console, potentially failing the build.
72   * It can also be configured to re-use an earlier analysis.
73   *
74   * @author <a href="mailto:joakim@erdfelt.net">Joakim Erdfelt</a>
75   * @version $Id: CheckstyleViolationCheckMojo.java 1663881 2015-03-04 08:10:45Z dennisl $
76   */
77  @Mojo( name = "check", defaultPhase = LifecyclePhase.VERIFY, requiresDependencyResolution = ResolutionScope.TEST,
78         threadSafe = true )
79  public class CheckstyleViolationCheckMojo
80      extends AbstractMojo
81  {
82  
83      private static final String JAVA_FILES = "**\\/*.java";
84  
85      private static final String CHECKSTYLE_FILE_HEADER = "<?xml version=\"1.0\"?>\n"
86              + "<!DOCTYPE module PUBLIC \"-//Puppy Crawl//DTD Check Configuration 1.2//EN\"\n"
87              + "        \"http://www.puppycrawl.com/dtds/configuration_1_2.dtd\">\n";
88  
89      /**
90       * Specifies the path and filename to save the Checkstyle output. The format
91       * of the output file is determined by the <code>outputFileFormat</code>
92       * parameter.
93       */
94      @Parameter( property = "checkstyle.output.file", defaultValue = "${project.build.directory}/checkstyle-result.xml" )
95      private File outputFile;
96  
97      /**
98       * Specifies the format of the output to be used when writing to the output
99       * file. Valid values are "<code>plain</code>" and "<code>xml</code>".
100      */
101     @Parameter( property = "checkstyle.output.format", defaultValue = "xml" )
102     private String outputFileFormat;
103 
104     /**
105      * Fail the build on a violation. The goal checks for the violations
106      * after logging them (if {@link #logViolationsToConsole} is 'true').
107      * Compare this to {@link #failsOnError} which fails the build immediately
108      * before examining the output log.
109      */
110     @Parameter( property = "checkstyle.failOnViolation", defaultValue = "true" )
111     private boolean failOnViolation;
112 
113     /**
114      * The maximum number of allowed violations. The execution fails only if the
115      * number of violations is above this limit.
116      *
117      * @since 2.3
118      */
119     @Parameter( property = "checkstyle.maxAllowedViolations", defaultValue = "0" )
120     private int maxAllowedViolations;
121 
122     /**
123      * The lowest severity level that is considered a violation.
124      * Valid values are "<code>error</code>", "<code>warning</code>" and "<code>info</code>".
125      *
126      * @since 2.2
127      */
128     @Parameter( property = "checkstyle.violationSeverity", defaultValue = "error" )
129     private String violationSeverity = "error";
130 
131     /**
132      * Violations to ignore. This is a comma-separated list, each value being either
133      * a rule name, a rule category or a java package name of rule class.
134      *
135      * @since 2.13
136      */
137     @Parameter( property = "checkstyle.violation.ignore" )
138     private String violationIgnore;
139 
140     /**
141      * Skip entire check.
142      *
143      * @since 2.2
144      */
145     @Parameter( property = "checkstyle.skip", defaultValue = "false" )
146     private boolean skip;
147 
148     /**
149      * Skip Checkstyle execution will only scan the outputFile.
150      *
151      * @since 2.5
152      */
153     @Parameter( property = "checkstyle.skipExec", defaultValue = "false" )
154     private boolean skipExec;
155 
156     /**
157      * Output the detected violations to the console.
158      *
159      * @since 2.3
160      */
161     @Parameter( property = "checkstyle.console", defaultValue = "true" )
162     private boolean logViolationsToConsole;
163 
164     /**
165      * Specifies the location of the resources to be used for Checkstyle.
166      *
167      * @since 2.11
168      */
169     @Parameter( defaultValue = "${project.resources}", readonly = true )
170     protected List<Resource> resources;
171 
172     /**
173      * <p>
174      * Specifies the location of the XML configuration to use.
175      * </p>
176      * <p/>
177      * <p>
178      * Potential values are a filesystem path, a URL, or a classpath resource.
179      * This parameter expects that the contents of the location conform to the
180      * xml format (Checkstyle <a
181      * href="http://checkstyle.sourceforge.net/config.html#Modules">Checker
182      * module</a>) configuration of rulesets.
183      * </p>
184      * <p/>
185      * <p>
186      * This parameter is resolved as resource, URL, then file. If successfully
187      * resolved, the contents of the configuration is copied into the
188      * <code>${project.build.directory}/checkstyle-configuration.xml</code>
189      * file before being passed to Checkstyle as a configuration.
190      * </p>
191      * <p/>
192      * <p>
193      * There are 2 predefined rulesets.
194      * </p>
195      * <ul>
196      * <li><code>config/sun_checks.xml</code>: Sun Checks.</li>
197      * <li><code>config/maven_checks.xml</code>: Maven Source Checks.</li>
198      * </ul>
199      *
200      * @since 2.5
201      */
202     @Parameter( property = "checkstyle.config.location", defaultValue = "config/sun_checks.xml" )
203     private String configLocation;
204 
205     /**
206      * <p>
207      * Specifies the location of the properties file.
208      * </p>
209      * <p/>
210      * <p>
211      * This parameter is resolved as URL, File then resource. If successfully
212      * resolved, the contents of the properties location is copied into the
213      * <code>${project.build.directory}/checkstyle-checker.properties</code>
214      * file before being passed to Checkstyle for loading.
215      * </p>
216      * <p/>
217      * <p>
218      * The contents of the <code>propertiesLocation</code> will be made
219      * available to Checkstyle for specifying values for parameters within the
220      * xml configuration (specified in the <code>configLocation</code>
221      * parameter).
222      * </p>
223      *
224      * @since 2.5
225      */
226     @Parameter( property = "checkstyle.properties.location" )
227     private String propertiesLocation;
228 
229     /**
230      * Allows for specifying raw property expansion information.
231      */
232     @Parameter
233     private String propertyExpansion;
234 
235     /**
236      * <p>
237      * Specifies the location of the License file (a.k.a. the header file) that
238      * can be used by Checkstyle to verify that source code has the correct
239      * license header.
240      * </p>
241      * <p>
242      * You need to use ${checkstyle.header.file} in your Checkstyle xml
243      * configuration to reference the name of this header file.
244      * </p>
245      * <p>
246      * For instance:
247      * </p>
248      * <p>
249      * <code>
250      * &lt;module name="RegexpHeader">
251      * &lt;property name="headerFile" value="${checkstyle.header.file}"/>
252      * &lt;/module>
253      * </code>
254      * </p>
255      *
256      * @since 2.0-beta-2
257      */
258     @Parameter( property = "checkstyle.header.file", defaultValue = "LICENSE.txt" )
259     private String headerLocation;
260 
261     /**
262      * Specifies the cache file used to speed up Checkstyle on successive runs.
263      */
264     @Parameter( defaultValue = "${project.build.directory}/checkstyle-cachefile" )
265     private String cacheFile;
266 
267     /**
268      * The key to be used in the properties for the suppressions file.
269      *
270      * @since 2.1
271      */
272     @Parameter( property = "checkstyle.suppression.expression", defaultValue = "checkstyle.suppressions.file" )
273     private String suppressionsFileExpression;
274 
275     /**
276      * <p>
277      * Specifies the location of the suppressions XML file to use.
278      * </p>
279      * <p/>
280      * <p>
281      * This parameter is resolved as resource, URL, then file. If successfully
282      * resolved, the contents of the suppressions XML is copied into the
283      * <code>${project.build.directory}/checkstyle-suppressions.xml</code> file
284      * before being passed to Checkstyle for loading.
285      * </p>
286      * <p/>
287      * <p>
288      * See <code>suppressionsFileExpression</code> for the property that will
289      * be made available to your Checkstyle configuration.
290      * </p>
291      *
292      * @since 2.0-beta-2
293      */
294     @Parameter( property = "checkstyle.suppressions.location" )
295     private String suppressionsLocation;
296 
297     /**
298      * The file encoding to use when reading the source files. If the property <code>project.build.sourceEncoding</code>
299      * is not set, the platform default encoding is used. <strong>Note:</strong> This parameter always overrides the
300      * property <code>charset</code> from Checkstyle's <code>TreeWalker</code> module.
301      *
302      * @since 2.2
303      */
304     @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
305     private String encoding;
306 
307     /**
308      * @since 2.5
309      */
310     @Component( role = CheckstyleExecutor.class, hint = "default" )
311     protected CheckstyleExecutor checkstyleExecutor;
312 
313     /**
314      * Output errors to console.
315      */
316     @Parameter( property = "checkstyle.consoleOutput", defaultValue = "false" )
317     private boolean consoleOutput;
318 
319     /**
320      * The Maven Project Object.
321      */
322     @Parameter ( defaultValue = "${project}", readonly = true, required = true )
323     protected MavenProject project;
324     
325     /**
326      * The Plugin Descriptor
327      */
328     @Parameter( defaultValue = "${plugin}", readonly = true, required = true )
329     private PluginDescriptor plugin;
330 
331     // remove when requiring Maven 3.x, just use #plugin 
332     @Parameter( defaultValue = "${mojoExecution}", readonly = true, required = true )
333     private MojoExecution mojoExecution;
334 
335     /**
336      * If <code>null</code>, the Checkstyle plugin will display violations on stdout.
337      * Otherwise, a text file will be created with the violations.
338      */
339     @Parameter
340     private File useFile;
341 
342     /**
343      * Specifies the names filter of the source files to be excluded for
344      * Checkstyle.
345      */
346     @Parameter( property = "checkstyle.excludes" )
347     private String excludes;
348 
349     /**
350      * Specifies the names filter of the source files to be used for Checkstyle.
351      */
352     @Parameter( property = "checkstyle.includes", defaultValue = JAVA_FILES, required = true )
353     private String includes;
354 
355     /**
356      * Specifies the names filter of the files to be excluded for
357      * Checkstyle when checking resources.
358      * @since 2.11
359      */
360     @Parameter( property = "checkstyle.resourceExcludes" )
361     private String resourceExcludes;
362 
363     /**
364      * Specifies the names filter of the files to be used for Checkstyle when checking resources.
365      * @since 2.11
366      */
367     @Parameter( property = "checkstyle.resourceIncludes", defaultValue = "**/*.properties", required = true )
368     private String resourceIncludes;
369 
370     /**
371      * If this is true, and Checkstyle reported any violations or errors,
372      * the build fails immediately after running Checkstyle, before checking the log
373      * for {@link #logViolationsToConsole}. If you want to use {@link #logViolationsToConsole},
374      * use {@link #failOnViolation} instead of this.
375      */
376     @Parameter( defaultValue = "false" )
377     private boolean failsOnError;
378 
379     /**
380      * Specifies the location of the test source directory to be used for
381      * Checkstyle.
382      *
383      * @since 2.2
384      * @deprecated instead use {@link #testSourceDirectories} 
385      */
386     @Deprecated
387     @Parameter
388     private File testSourceDirectory;
389 
390     /**
391      * Specifies the location of the test source directories to be used for
392      * Checkstyle.
393      * @since 2.13
394      */
395     @Parameter( defaultValue = "${project.testCompileSourceRoots}" )
396     private List<String> testSourceDirectories;
397 
398     /**
399      * Include or not the test source directory to be used for Checkstyle.
400      *
401      * @since 2.2
402      */
403     @Parameter( defaultValue = "false" )
404     private boolean includeTestSourceDirectory;
405 
406     /**
407      * Specifies the location of the source directory to be used for Checkstyle.
408      * 
409      * @deprecated instead use {@link #sourceDirectories}
410      */
411     @Deprecated
412     @Parameter
413     private File sourceDirectory;
414 
415     /**
416      * Specifies the location of the source directories to be used for Checkstyle.
417      * @since 2.13
418      */
419     @Parameter( defaultValue = "${project.compileSourceRoots}" )
420     private List<String> sourceDirectories;
421 
422     /**
423      * Whether to apply Checkstyle to resource directories.
424      * @since 2.11
425      */
426     @Parameter( property = "checkstyle.includeResources", defaultValue = "true", required = true )
427     private boolean includeResources = true;
428 
429     /**
430      * Whether to apply Checkstyle to test resource directories.
431      * @since 2.11
432      */
433     @Parameter( property = "checkstyle.includeTestResources", defaultValue = "true", required = true )
434     private boolean includeTestResources = true;
435 
436     /**
437      * By using this property, you can specify the whole Checkstyle rules
438      * inline directly inside this pom.
439      *
440      * <pre>
441      * &lt;plugin&gt;
442      *   ...
443      *   &lt;configuration&gt;
444      *     &lt;checkstyleRules&gt;
445      *       &lt;module name="Checker"&gt;
446      *         &lt;module name="FileTabCharacter"&gt;
447      *           &lt;property name="eachLine" value="true" /&gt;
448      *         &lt;/module&gt;
449      *         &lt;module name="TreeWalker"&gt;
450      *           &lt;module name="EmptyBlock"/&gt;
451      *         &lt;/module&gt;
452      *       &lt;/module&gt;
453      *     &lt;/checkstyleRules&gt;
454      *   &lt;/configuration&gt;
455      *   ...
456      * </pre>
457      *
458      * @since 2.12
459      */
460     @Parameter
461     private PlexusConfiguration checkstyleRules;
462 
463     /**
464      * dump file for inlined Checkstyle rules 
465      */
466     @Parameter( property = "checkstyle.output.rules.file",
467                     defaultValue = "${project.build.directory}/checkstyle-rules.xml" )
468     private File rulesFiles;
469 
470     private ByteArrayOutputStream stringOutputStream;
471 
472     /** {@inheritDoc} */
473     public void execute()
474         throws MojoExecutionException, MojoFailureException
475     {
476         if ( skip )
477         {
478             return;
479         }
480 
481         if ( !skipExec )
482         {
483             if ( checkstyleRules != null )
484             {
485                 if ( !"config/sun_checks.xml".equals( configLocation ) )
486                 {
487                     throw new MojoExecutionException( "If you use inline configuration for rules, don't specify "
488                         + "a configLocation" );
489                 }
490                 if ( checkstyleRules.getChildCount() > 1 )
491                 {
492                     throw new MojoExecutionException( "Currently only one root module is supported" );
493                 }
494 
495                 PlexusConfiguration checkerModule = checkstyleRules.getChild( 0 );
496 
497                 try
498                 {
499                     FileUtils.forceMkdir( rulesFiles.getParentFile() );
500                     FileUtils.fileWrite( rulesFiles, CHECKSTYLE_FILE_HEADER + checkerModule.toString() );
501                 }
502                 catch ( final IOException e )
503                 {
504                     throw new MojoExecutionException( e.getMessage(), e );
505                 }
506                 configLocation = rulesFiles.getAbsolutePath();
507             }
508 
509             ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
510 
511             try
512             {
513                 CheckstyleExecutorRequest request = new CheckstyleExecutorRequest();
514                 request.setConsoleListener( getConsoleListener() ).setConsoleOutput( consoleOutput )
515                     .setExcludes( excludes ).setFailsOnError( failsOnError ).setIncludes( includes )
516                     .setResourceIncludes( resourceIncludes )
517                     .setResourceExcludes( resourceExcludes )
518                     .setIncludeResources( includeResources )
519                     .setIncludeTestResources( includeTestResources )
520                     .setIncludeTestSourceDirectory( includeTestSourceDirectory ).setListener( getListener() )
521                     .setProject( project ).setSourceDirectories( getSourceDirectories() )
522                     .setResources( resources )
523                     .setStringOutputStream( stringOutputStream ).setSuppressionsLocation( suppressionsLocation )
524                     .setTestSourceDirectories( getTestSourceDirectories() ).setConfigLocation( configLocation )
525                     .setConfigurationArtifacts( collectArtifacts( "config" ) )
526                     .setPropertyExpansion( propertyExpansion )
527                     .setHeaderLocation( headerLocation ).setLicenseArtifacts( collectArtifacts( "license" ) )
528                     .setCacheFile( cacheFile ).setSuppressionsFileExpression( suppressionsFileExpression )
529                     .setEncoding( encoding ).setPropertiesLocation( propertiesLocation );
530                 checkstyleExecutor.executeCheckstyle( request );
531 
532             }
533             catch ( CheckstyleException e )
534             {
535                 throw new MojoExecutionException( "Failed during checkstyle configuration", e );
536             }
537             catch ( CheckstyleExecutorException e )
538             {
539                 throw new MojoExecutionException( "Failed during checkstyle execution", e );
540             }
541             finally
542             {
543                 //be sure to restore original context classloader
544                 Thread.currentThread().setContextClassLoader( currentClassLoader );
545             }
546         }
547 
548         if ( !"xml".equals( outputFileFormat ) )
549         {
550             throw new MojoExecutionException( "Output format is '" + outputFileFormat
551                 + "', checkstyle:check requires format to be 'xml'." );
552         }
553 
554         if ( !outputFile.exists() )
555         {
556             getLog().info( "Unable to perform checkstyle:check, unable to find checkstyle:checkstyle outputFile." );
557             return;
558         }
559 
560         Reader reader = null;
561         try
562         {
563             reader = new BufferedReader( ReaderFactory.newXmlReader( outputFile ) );
564 
565             XmlPullParser xpp = new MXParser();
566             xpp.setInput( reader );
567 
568             int violations = countViolations( xpp );
569 
570             if ( violations > maxAllowedViolations )
571             {
572                 if ( failOnViolation )
573                 {
574                     String msg =
575                         "You have " + violations + " Checkstyle violation" + ( ( violations > 1 ) ? "s" : "" ) + ".";
576                     if ( maxAllowedViolations > 0 )
577                     {
578                         msg += " The maximum number of allowed violations is " + maxAllowedViolations + ".";
579                     }
580                     throw new MojoFailureException( msg );
581                 }
582 
583                 getLog().warn( "checkstyle:check violations detected but failOnViolation set to false" );
584             }
585         }
586         catch ( IOException e )
587         {
588             throw new MojoExecutionException( "Unable to read Checkstyle results xml: " + outputFile.getAbsolutePath(),
589                                               e );
590         }
591         catch ( XmlPullParserException e )
592         {
593             throw new MojoExecutionException( "Unable to read Checkstyle results xml: " + outputFile.getAbsolutePath(),
594                                               e );
595         }
596         finally
597         {
598             IOUtil.close( reader );
599         }
600     }
601 
602     private int countViolations( XmlPullParser xpp )
603         throws XmlPullParserException, IOException
604     {
605         int count = 0;
606         int ignoreCount = 0;
607         RuleUtil.Matcher[] ignores =
608             ( violationIgnore == null ) ? null : RuleUtil.parseMatchers( violationIgnore.split( "," ) );
609 
610         String basedir = project.getBasedir().getAbsolutePath();
611         String file = "";
612         for ( int eventType = xpp.getEventType(); eventType != XmlPullParser.END_DOCUMENT; eventType = xpp.next() )
613         {
614             if ( eventType != XmlPullParser.START_TAG )
615             {
616                 continue;
617             }
618             else if ( "file".equals( xpp.getName() ) )
619             {
620                 file = PathTool.getRelativeFilePath( basedir, xpp.getAttributeValue( "", "name" ) );
621                 //file = file.substring( file.lastIndexOf( File.separatorChar ) + 1 );
622             }
623             else if ( "error".equals( xpp.getName() ) )
624             {
625                 String severity = xpp.getAttributeValue( "", "severity" );
626 
627                 if ( !isViolation( severity ) )
628                 {
629                     continue;
630                 }
631 
632                 String source = xpp.getAttributeValue( "", "source" );
633 
634                 if ( ignore( ignores, source ) )
635                 {
636                     ignoreCount++;
637                 }
638                 else
639                 {
640                     count++;
641 
642                     if ( logViolationsToConsole )
643                     {
644                         String line = xpp.getAttributeValue( "", "line" );
645                         String column = xpp.getAttributeValue( "", "column" );
646                         String message = xpp.getAttributeValue( "", "message" );
647                         String rule = RuleUtil.getName( source );
648                         String category = RuleUtil.getCategory( source );
649 
650                         log( severity, file + '[' + line + ( ( column == null ) ? "" : ( ':' + column ) ) + "] ("
651                             + category + ") " + rule + ": " + message );
652                     }
653                 }
654             }
655         }
656 
657         if ( ignoreCount > 0 )
658         {
659             getLog().info( "Ignored " + ignoreCount + " error" + ( ( ignoreCount > 1 ) ? "s" : "" ) + ", " + count
660                                + " violation" + ( ( count > 1 ) ? "s" : "" ) + " remaining." );
661         }
662 
663         return count;
664     }
665 
666     private void log( String severity, String message )
667     {
668         if ( "info".equals( severity ) )
669         {
670             getLog().info( message );
671         }
672         else if ( "warning".equals( severity ) )
673         {
674             getLog().warn( message );
675         }
676         else
677         {
678             getLog().error( message );
679         }
680     }
681 
682     /**
683      * Checks if the given severity is considered a violation.
684      *
685      * @param severity The severity to check
686      * @return <code>true</code> if the given severity is a violation, otherwise <code>false</code>
687      */
688     private boolean isViolation( String severity )
689     {
690         if ( "error".equals( severity ) )
691         {
692             return "error".equals( violationSeverity ) || "warning".equals( violationSeverity )
693                 || "info".equals( violationSeverity );
694         }
695         else if ( "warning".equals( severity ) )
696         {
697             return "warning".equals( violationSeverity ) || "info".equals( violationSeverity );
698         }
699         else if ( "info".equals( severity ) )
700         {
701             return "info".equals( violationSeverity );
702         }
703         else
704         {
705             return false;
706         }
707     }
708 
709     private boolean ignore( RuleUtil.Matcher[] ignores, String source )
710     {
711         if ( ignores != null )
712         {
713             for ( RuleUtil.Matcher ignore : ignores )
714             {
715                 if ( ignore.match( source ) )
716                 {
717                     return true;
718                 }
719             }
720         }
721 
722         return false;
723     }
724 
725     private DefaultLogger getConsoleListener()
726         throws MojoExecutionException
727     {
728         DefaultLogger consoleListener;
729 
730         if ( useFile == null )
731         {
732             stringOutputStream = new ByteArrayOutputStream();
733             consoleListener = new DefaultLogger( stringOutputStream, false );
734         }
735         else
736         {
737             OutputStream out = getOutputStream( useFile );
738 
739             consoleListener = new DefaultLogger( out, true );
740         }
741 
742         return consoleListener;
743     }
744 
745     private OutputStream getOutputStream( File file )
746         throws MojoExecutionException
747     {
748         File parentFile = file.getAbsoluteFile().getParentFile();
749 
750         if ( !parentFile.exists() )
751         {
752             parentFile.mkdirs();
753         }
754 
755         FileOutputStream fileOutputStream;
756         try
757         {
758             fileOutputStream = new FileOutputStream( file );
759         }
760         catch ( FileNotFoundException e )
761         {
762             throw new MojoExecutionException( "Unable to create output stream: " + file, e );
763         }
764         return fileOutputStream;
765     }
766 
767     private AuditListener getListener()
768         throws MojoFailureException, MojoExecutionException
769     {
770         AuditListener listener = null;
771 
772         if ( StringUtils.isNotEmpty( outputFileFormat ) )
773         {
774             File resultFile = outputFile;
775 
776             OutputStream out = getOutputStream( resultFile );
777 
778             if ( "xml".equals( outputFileFormat ) )
779             {
780                 listener = new XMLLogger( out, true );
781             }
782             else if ( "plain".equals( outputFileFormat ) )
783             {
784                 listener = new DefaultLogger( out, true );
785             }
786             else
787             {
788                 throw new MojoFailureException( "Invalid output file format: (" + outputFileFormat
789                     + "). Must be 'plain' or 'xml'." );
790             }
791         }
792 
793         return listener;
794     }
795     
796     @SuppressWarnings( "unchecked" )
797     private List<Artifact> collectArtifacts( String hint )
798     {
799         if ( plugin == null || plugin.getGroupId() == null )
800         {
801             // Maven 2.x workaround
802             plugin = mojoExecution.getMojoDescriptor().getPluginDescriptor();
803         }
804         
805         List<Artifact> artifacts = new ArrayList<Artifact>();
806 
807         PluginManagement pluginManagement = project.getBuild().getPluginManagement();
808         if ( pluginManagement != null )
809         {
810             artifacts.addAll( getCheckstylePluginDependenciesAsArtifacts( pluginManagement.getPluginsAsMap(), hint ) );
811         }
812 
813         artifacts.addAll( getCheckstylePluginDependenciesAsArtifacts( project.getBuild().getPluginsAsMap(), hint ) );
814 
815         return artifacts;
816     }
817 
818     private List<Artifact> getCheckstylePluginDependenciesAsArtifacts( Map<String, Plugin> plugins, String hint )
819     {
820         List<Artifact> artifacts = new ArrayList<Artifact>();
821         
822         Plugin checkstylePlugin = plugins.get( plugin.getGroupId() + ":" + plugin.getArtifactId() );
823         if ( checkstylePlugin != null )
824         {
825             for ( Dependency dep : checkstylePlugin.getDependencies() )
826             {
827              // @todo if we can filter on hints, it should be done here...
828                 String depKey = dep.getGroupId() + ":" + dep.getArtifactId();
829                 artifacts.add( (Artifact) plugin.getArtifactMap().get( depKey ) );
830             }
831         }
832         return artifacts;
833     }
834     
835     private List<File> getSourceDirectories()
836     {
837         List<File> sourceDirs = null;
838         // if sourceDirectory is explicitly set, use it
839         if ( sourceDirectory != null )
840         {
841             sourceDirs = Collections.singletonList( sourceDirectory );
842         }
843         else
844         {
845             sourceDirs = new ArrayList<File>( sourceDirectories.size() );
846             for ( String sourceDir : sourceDirectories )
847             {
848                 sourceDirs.add( FileUtils.resolveFile( project.getBasedir(), sourceDir ) );
849             }
850         }
851         
852         return sourceDirs;
853     }
854     
855     private List<File> getTestSourceDirectories()
856     {
857         List<File> testSourceDirs = null;
858         // if testSourceDirectory is explicitly set, use it
859         if ( testSourceDirectory != null )
860         {
861             testSourceDirs = Collections.singletonList( testSourceDirectory );
862         }
863         // probably null-check only required due to MavenProjectStubs
864         else if ( testSourceDirectories != null )
865         {
866             testSourceDirs = new ArrayList<File>( testSourceDirectories.size() );
867             for ( String testSourceDir : testSourceDirectories )
868             {
869                 testSourceDirs.add( FileUtils.resolveFile( project.getBasedir(), testSourceDir ) );
870             }
871         }
872         
873         return testSourceDirs;
874     }
875     
876 }