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