View Javadoc
1   package org.apache.maven.plugins.checkstyle.exec;
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.ByteArrayInputStream;
23  import java.io.File;
24  import java.io.FileInputStream;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.net.MalformedURLException;
28  import java.net.URL;
29  import java.net.URLClassLoader;
30  import java.security.AccessController;
31  import java.security.PrivilegedAction;
32  import java.util.ArrayList;
33  import java.util.Collection;
34  import java.util.HashMap;
35  import java.util.LinkedHashSet;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.Properties;
39  import java.util.Set;
40  
41  import org.apache.commons.io.IOUtils;
42  import org.apache.maven.artifact.Artifact;
43  import org.apache.maven.artifact.DependencyResolutionRequiredException;
44  import org.apache.maven.model.Resource;
45  import org.apache.maven.project.MavenProject;
46  import org.codehaus.plexus.component.annotations.Component;
47  import org.codehaus.plexus.component.annotations.Requirement;
48  import org.codehaus.plexus.logging.AbstractLogEnabled;
49  import org.codehaus.plexus.resource.ResourceManager;
50  import org.codehaus.plexus.resource.loader.FileResourceCreationException;
51  import org.codehaus.plexus.resource.loader.FileResourceLoader;
52  import org.codehaus.plexus.resource.loader.ResourceNotFoundException;
53  import org.codehaus.plexus.util.FileUtils;
54  import org.codehaus.plexus.util.StringUtils;
55  
56  import com.puppycrawl.tools.checkstyle.Checker;
57  import com.puppycrawl.tools.checkstyle.ConfigurationLoader;
58  import com.puppycrawl.tools.checkstyle.ConfigurationLoader.IgnoredModulesOptions;
59  import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
60  import com.puppycrawl.tools.checkstyle.PackageNamesLoader;
61  import com.puppycrawl.tools.checkstyle.PropertiesExpander;
62  import com.puppycrawl.tools.checkstyle.api.AuditListener;
63  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
64  import com.puppycrawl.tools.checkstyle.api.Configuration;
65  import com.puppycrawl.tools.checkstyle.api.FilterSet;
66  import com.puppycrawl.tools.checkstyle.filters.SuppressionsLoader;
67  
68  /**
69   * @author Olivier Lamy
70   * @since 2.5
71   *
72   */
73  @Component( role = CheckstyleExecutor.class, hint = "default", instantiationStrategy = "per-lookup" )
74  public class DefaultCheckstyleExecutor
75      extends AbstractLogEnabled
76      implements CheckstyleExecutor
77  {
78      @Requirement( hint = "default" )
79      private ResourceManager locator;
80      
81      @Requirement( hint = "license" )
82      private ResourceManager licenseLocator;
83  
84      public CheckstyleResults executeCheckstyle( CheckstyleExecutorRequest request )
85          throws CheckstyleExecutorException, CheckstyleException
86      {
87          if ( getLogger().isDebugEnabled() )
88          {
89              getLogger().debug( "executeCheckstyle start headerLocation : " + request.getHeaderLocation() );
90          }
91  
92          MavenProject project = request.getProject();
93  
94          configureResourceLocator( locator, request, null );
95          
96          configureResourceLocator( licenseLocator, request, request.getLicenseArtifacts() );
97  
98          // Config is less critical than License, locator can still be used.
99          // configureResourceLocator( configurationLocator, request, request.getConfigurationArtifacts() );
100 
101         List<File> files;
102         try
103         {
104             files = getFilesToProcess( request );
105         }
106         catch ( IOException e )
107         {
108             throw new CheckstyleExecutorException( "Error getting files to process", e );
109         }
110 
111         final String suppressionsFilePath = getSuppressionsFilePath( request );
112         FilterSet filterSet = getSuppressionsFilterSet( suppressionsFilePath );
113 
114         Checker checker = new Checker();
115 
116         // setup classloader, needed to avoid "Unable to get class information for ..." errors
117         List<String> classPathStrings = new ArrayList<>();
118         List<String> outputDirectories = new ArrayList<>();
119         
120         // stand-alone
121         Collection<File> sourceDirectories = null;
122         Collection<File> testSourceDirectories = request.getTestSourceDirectories();
123         
124         // aggregator
125         Map<MavenProject, Collection<File>> sourceDirectoriesByProject = new HashMap<>();
126         Map<MavenProject, Collection<File>> testSourceDirectoriesByProject = new HashMap<>();
127         
128         if ( request.isAggregate() )
129         {
130             for ( MavenProject childProject : request.getReactorProjects() )
131             {
132                 sourceDirectories = new ArrayList<>( childProject.getCompileSourceRoots().size() );
133                 List<String> compileSourceRoots = childProject.getCompileSourceRoots();
134                 for ( String compileSourceRoot : compileSourceRoots )
135                 {
136                     sourceDirectories.add( new File( compileSourceRoot ) );
137                 }
138                 sourceDirectoriesByProject.put( childProject, sourceDirectories );
139                 
140                 testSourceDirectories = new ArrayList<>( childProject.getTestCompileSourceRoots().size() );
141                 List<String> testCompileSourceRoots = childProject.getTestCompileSourceRoots();
142                 for ( String testCompileSourceRoot : testCompileSourceRoots )
143                 {
144                     testSourceDirectories.add( new File( testCompileSourceRoot ) );
145                 }
146                 testSourceDirectoriesByProject.put( childProject, testSourceDirectories );
147                 
148                 prepareCheckstylePaths( request, childProject, classPathStrings, outputDirectories,
149                                         sourceDirectories, testSourceDirectories );
150             }
151         }
152         else
153         {
154             sourceDirectories = request.getSourceDirectories();
155             prepareCheckstylePaths( request, project, classPathStrings, outputDirectories, sourceDirectories,
156                                     testSourceDirectories );
157         }
158 
159         setUpCheckstyleClassloader( checker, classPathStrings, outputDirectories );
160 
161         checker.setModuleClassLoader( Thread.currentThread().getContextClassLoader() );
162 
163         if ( filterSet != null )
164         {
165             checker.addFilter( filterSet );
166         }
167         Configuration configuration = getConfiguration( request );
168         checker.configure( configuration );
169 
170         AuditListener listener = request.getListener();
171 
172         if ( listener != null )
173         {
174             checker.addListener( listener );
175         }
176 
177         if ( request.isConsoleOutput() )
178         {
179             checker.addListener( request.getConsoleListener() );
180         }
181 
182         CheckstyleCheckerListener checkerListener = new CheckstyleCheckerListener( configuration );
183         if ( request.isAggregate() )
184         {
185             for ( MavenProject childProject : request.getReactorProjects() )
186             {
187                 sourceDirectories = sourceDirectoriesByProject.get( childProject );
188                 testSourceDirectories = testSourceDirectoriesByProject.get( childProject );
189                 addSourceDirectory( checkerListener, sourceDirectories,
190                                     testSourceDirectories,
191                                     childProject.getResources(), request );
192             }
193         }
194         else
195         {
196             addSourceDirectory( checkerListener, sourceDirectories, testSourceDirectories, request.getResources(),
197                                 request );
198         }
199 
200         checker.addListener( checkerListener );
201 
202         int nbErrors = checker.process( files );
203 
204         checker.destroy();
205 
206         if ( request.getStringOutputStream() != null )
207         {
208             String message = request.getStringOutputStream().toString().trim();
209 
210             if ( message.length() > 0 )
211             {
212                 getLogger().info( message );
213             }
214         }
215 
216         if ( nbErrors > 0 )
217         {
218             StringBuilder message = new StringBuilder( "There " );
219             if ( nbErrors == 1 )
220             {
221                 message.append( "is" );
222             }
223             else
224             {
225                 message.append( "are" );
226             }
227             message.append( " " );
228             message.append( nbErrors );
229             message.append( " error" );
230             if ( nbErrors != 1 )
231             {
232                 message.append( "s" );
233             }
234             message.append( " reported by Checkstyle" );
235             String version = getCheckstyleVersion();
236             if ( version != null )
237             {
238                 message.append( " " );
239                 message.append( version );
240             }
241             message.append( " with " );
242             message.append( request.getConfigLocation() );
243             message.append( " ruleset." );
244 
245             if ( request.isFailsOnError() )
246             {
247                 // TODO: should be a failure, not an error. Report is not meant to
248                 // throw an exception here (so site would
249                 // work regardless of config), but should record this information
250                 throw new CheckstyleExecutorException( message.toString() );
251             }
252             else
253             {
254                 getLogger().info( message.toString() );
255             }
256         }
257 
258         return checkerListener.getResults();
259     }
260 
261     private void setUpCheckstyleClassloader( Checker checker,
262                                              List<String> classPathStrings,
263                                              List<String> outputDirectories )
264         throws CheckstyleExecutorException
265     {
266         final List<URL> urls = new ArrayList<>( classPathStrings.size() );
267 
268         for ( String path : classPathStrings )
269         {
270             try
271             {
272                 urls.add( new File( path ).toURI().toURL() );
273             }
274             catch ( MalformedURLException e )
275             {
276                 throw new CheckstyleExecutorException( e.getMessage(), e );
277             }
278         }
279 
280         for ( String outputDirectoryString : outputDirectories )
281         {
282             try
283             {
284                 if ( outputDirectoryString != null )
285                 {
286                     File outputDirectoryFile = new File( outputDirectoryString );
287                     if ( outputDirectoryFile.exists() )
288                     {
289                         URL outputDirectoryUrl = outputDirectoryFile.toURI().toURL();
290                         getLogger().debug( "Adding the outputDirectory " + outputDirectoryUrl.toString()
291                                                + " to the Checkstyle class path" );
292                         urls.add( outputDirectoryUrl );
293                     }
294                 }
295             }
296             catch ( MalformedURLException e )
297             {
298                 throw new CheckstyleExecutorException( e.getMessage(), e );
299             }
300         }
301 
302         URLClassLoader projectClassLoader = AccessController.doPrivileged( new PrivilegedAction<URLClassLoader>()
303         {
304             public URLClassLoader run()
305             {
306                 return new URLClassLoader( urls.toArray( new URL[0] ), null );
307             }
308         } );
309 
310         /*
311          * MCHECKSTYLE-381: More recent Checkstyle versions will drop the setClassLoader() method.
312          * However, it was used before Checkstyle 8.25.
313          */
314         try
315         {
316             checker.setClassLoader( projectClassLoader );
317         }
318         catch ( NoSuchMethodError ignored )
319         {
320             /*
321              * The current checkstyle version does not support the method setClassLoader anymore.
322              * This is expected. The method call is being retained for less recent versions of checkstyle.
323              */
324         }
325 
326     }
327 
328     protected void addSourceDirectory( CheckstyleCheckerListener sinkListener, Collection<File> sourceDirectories,
329                                        Collection<File> testSourceDirectories, List<Resource> resources,
330                                        CheckstyleExecutorRequest request )
331     {
332         if ( sourceDirectories != null )
333         {
334             for ( File sourceDirectory : sourceDirectories )
335             {
336                 if ( sourceDirectory.exists() )
337                 {
338                     sinkListener.addSourceDirectory( sourceDirectory );
339                 }
340             }
341         }
342 
343         if ( request.isIncludeTestSourceDirectory() && ( testSourceDirectories != null ) )
344         {
345             for ( File testSourceDirectory : testSourceDirectories )
346             {
347                 if ( testSourceDirectory.isDirectory() )
348                 {
349                     sinkListener.addSourceDirectory( testSourceDirectory );
350                 }
351             }
352         }
353 
354         if ( resources != null )
355         {
356             for ( Resource resource : resources )
357             {
358                 if ( resource.getDirectory() != null )
359                 {
360                     File resourcesDirectory = new File( resource.getDirectory() );
361                     if ( resourcesDirectory.exists() && resourcesDirectory.isDirectory() )
362                     {
363                         sinkListener.addSourceDirectory( resourcesDirectory );
364                         getLogger().debug( "Added '" + resourcesDirectory.getAbsolutePath()
365                                 + "' as a source directory." );
366                     }
367                 }
368             }
369         }
370     }
371 
372     public Configuration getConfiguration( CheckstyleExecutorRequest request )
373         throws CheckstyleExecutorException
374     {
375         try
376         {
377             // Checkstyle will always use the context classloader in order
378             // to load resources (dtds),
379             // so we have to fix it
380             ClassLoader checkstyleClassLoader = PackageNamesLoader.class.getClassLoader();
381             Thread.currentThread().setContextClassLoader( checkstyleClassLoader );
382             String configFile = getConfigFile( request );
383             Properties overridingProperties = getOverridingProperties( request );
384             IgnoredModulesOptions omitIgnoredModules;
385             if ( request.isOmitIgnoredModules() )
386             {
387                 omitIgnoredModules = IgnoredModulesOptions.OMIT;
388             }
389             else
390             {
391                 omitIgnoredModules = IgnoredModulesOptions.EXECUTE;
392             }
393             Configuration config =
394                 ConfigurationLoader.loadConfiguration( configFile, new PropertiesExpander( overridingProperties ),
395                                                        omitIgnoredModules );
396             String effectiveEncoding = StringUtils.isNotEmpty( request.getEncoding() ) ? request.getEncoding() : System
397                 .getProperty( "file.encoding", "UTF-8" );
398             
399             if ( StringUtils.isEmpty( request.getEncoding() ) )
400             {
401                 getLogger().warn( "File encoding has not been set, using platform encoding " + effectiveEncoding
402                                       + ", i.e. build is platform dependent!" );
403             }
404 
405             if ( "Checker".equals( config.getName() )
406                     || "com.puppycrawl.tools.checkstyle.Checker".equals( config.getName() ) )
407             {
408                 if ( config instanceof DefaultConfiguration )
409                 {
410                     // MCHECKSTYLE-173 Only add the "charset" attribute if it has not been set
411                     addAttributeIfNotExists( (DefaultConfiguration) config, "charset", effectiveEncoding );
412                     addAttributeIfNotExists( (DefaultConfiguration) config, "cacheFile", request.getCacheFile() );
413                 }
414                 else
415                 {
416                     getLogger().warn( "Failed to configure file encoding on module " + config );
417                 }
418             }
419             return config;
420         }
421         catch ( CheckstyleException e )
422         {
423             throw new CheckstyleExecutorException( "Failed during checkstyle configuration", e );
424         }
425     }
426 
427     private void addAttributeIfNotExists( DefaultConfiguration config, String name, String value )
428     {
429         try
430         {
431             // MCHECKSTYLE-132 DefaultConfiguration addAttribute has changed in checkstyle 5.3
432             if ( config.getAttribute( name ) == null )
433             {
434                 config.addAttribute( name, value );
435             }
436         }
437         catch ( CheckstyleException ex )
438         {
439             // MCHECKSTYLE-159 Checkstyle 5.4+ throws an exception when trying to access an attribute that doesn't exist
440             config.addAttribute( name, value );
441         }
442     }
443 
444     private void prepareCheckstylePaths( CheckstyleExecutorRequest request, MavenProject project,
445                                          List<String> classPathStrings, List<String> outputDirectories,
446                                          Collection<File> sourceDirectories, Collection<File> testSourceDirectories )
447         throws CheckstyleExecutorException
448     {
449         try
450         {
451             outputDirectories.add( project.getBuild().getOutputDirectory() );
452 
453             if ( request.isIncludeTestSourceDirectory() && ( testSourceDirectories != null )
454                 && anyDirectoryExists( testSourceDirectories ) )
455             {
456                 classPathStrings.addAll( project.getTestClasspathElements() );
457                 outputDirectories.add( project.getBuild().getTestOutputDirectory() );
458             }
459             else
460             {
461                 classPathStrings.addAll( project.getCompileClasspathElements() );
462             }
463         }
464         catch ( DependencyResolutionRequiredException e )
465         {
466             throw new CheckstyleExecutorException( e.getMessage(), e );
467         }
468     }
469     
470     private boolean anyDirectoryExists( Collection<File> files )
471     {
472         for ( File file : files )
473         {
474             if ( file.isDirectory() )
475             {
476                 return true;
477             }
478         }
479         return false;
480     }
481 
482     /**
483      * Get the effective Checkstyle version at runtime.
484      * @return the MANIFEST implementation version of Checkstyle API package (can be <code>null</code>)
485      *
486      *@todo Copied from CheckstyleReportGenerator - move to a utility class
487      */
488     private String getCheckstyleVersion()
489     {
490         Package checkstyleApiPackage = Configuration.class.getPackage();
491 
492         return ( checkstyleApiPackage == null ) ? null : checkstyleApiPackage.getImplementationVersion();
493     }
494 
495     private Properties getOverridingProperties( CheckstyleExecutorRequest request )
496         throws CheckstyleExecutorException
497     {
498         Properties p = new Properties();
499         InputStream in = null;
500         try
501         {
502             if ( request.getPropertiesLocation() != null )
503             {
504                 if ( getLogger().isDebugEnabled() )
505                 {
506                     getLogger().debug( "request.getPropertiesLocation() " + request.getPropertiesLocation() );
507                 }
508 
509                 File propertiesFile = locator.getResourceAsFile( request.getPropertiesLocation(),
510                                                                  "checkstyle-checker.properties" );
511 
512                 if ( propertiesFile != null )
513                 {
514                     in = new FileInputStream( propertiesFile );
515                     p.load( in );
516                     in.close();
517                     in = null;
518                 }
519             }
520 
521             if ( StringUtils.isNotEmpty( request.getPropertyExpansion() ) )
522             {
523                 String propertyExpansion = request.getPropertyExpansion();
524                 // Convert \ to \\, so that p.load will convert it back properly
525                 propertyExpansion = StringUtils.replace( propertyExpansion, "\\", "\\\\" );
526                 p.load( new ByteArrayInputStream( propertyExpansion.getBytes() ) );
527             }
528 
529             // Workaround for MCHECKSTYLE-48
530             // Make sure that "config/maven-header.txt" is the default value
531             // for headerLocation, if configLocation="config/maven_checks.xml"
532             String headerLocation = request.getHeaderLocation();
533             if ( "config/maven_checks.xml".equals( request.getConfigLocation() ) )
534             {
535 
536                 if ( "LICENSE.txt".equals( request.getHeaderLocation() ) )
537                 {
538                     headerLocation = "config/maven-header.txt";
539                 }
540             }
541             if ( getLogger().isDebugEnabled() )
542             {
543                 getLogger().debug( "headerLocation " + headerLocation );
544             }
545 
546             if ( StringUtils.isNotEmpty( headerLocation ) )
547             {
548                 try
549                 {
550                     File headerFile = licenseLocator.getResourceAsFile( headerLocation, "checkstyle-header.txt" );
551 
552                     if ( headerFile != null )
553                     {
554                         p.setProperty( "checkstyle.header.file", headerFile.getAbsolutePath() );
555                     }
556                 }
557                 catch ( FileResourceCreationException | ResourceNotFoundException e )
558                 {
559                     getLogger().debug( "Unable to process header location: " + headerLocation );
560                     getLogger().debug( "Checkstyle will throw exception if ${checkstyle.header.file} is used" );
561                 }
562             }
563 
564             if ( request.getCacheFile() != null )
565             {
566                 p.setProperty( "checkstyle.cache.file", request.getCacheFile() );
567             }
568         }
569         catch ( IOException | ResourceNotFoundException | FileResourceCreationException e )
570         {
571             throw new CheckstyleExecutorException( "Failed to get overriding properties", e );
572         }
573         finally
574         {
575             IOUtils.closeQuietly( in );
576         }
577         if ( request.getSuppressionsFileExpression() != null )
578         {
579             String suppressionsFilePath = getSuppressionsFilePath( request );
580 
581             if ( suppressionsFilePath != null )
582             {
583                 p.setProperty( request.getSuppressionsFileExpression(), suppressionsFilePath );
584             }
585         }
586 
587         return p;
588     }
589 
590     private List<File> getFilesToProcess( CheckstyleExecutorRequest request )
591         throws IOException
592     {
593         StringBuilder excludesStr = new StringBuilder();
594 
595         if ( StringUtils.isNotEmpty( request.getExcludes() ) )
596         {
597             excludesStr.append( request.getExcludes() );
598         }
599 
600         String[] defaultExcludes = FileUtils.getDefaultExcludes();
601         for ( String defaultExclude : defaultExcludes )
602         {
603             if ( excludesStr.length() > 0 )
604             {
605                 excludesStr.append( "," );
606             }
607 
608             excludesStr.append( defaultExclude );
609         }
610 
611         Set<File> files = new LinkedHashSet<>();
612         if ( request.isAggregate() )
613         {
614             for ( MavenProject project : request.getReactorProjects() )
615             {
616                 Set<File> sourceDirectories = new LinkedHashSet<>();
617                 
618                 // CompileSourceRoots are absolute paths
619                 List<String> compileSourceRoots = project.getCompileSourceRoots(); 
620                 for ( String compileSourceRoot : compileSourceRoots )
621                 {
622                     sourceDirectories.add( new File( compileSourceRoot ) );
623                 }
624 
625                 Set<File> testSourceDirectories = new LinkedHashSet<>();
626                 // CompileSourceRoots are absolute paths
627                 List<String> testCompileSourceRoots = project.getTestCompileSourceRoots(); 
628                 for ( String testCompileSourceRoot : testCompileSourceRoots )
629                 {
630                     testSourceDirectories.add( new File( testCompileSourceRoot ) );
631                 }
632 
633                 addFilesToProcess( request, sourceDirectories, project.getResources(), project.getTestResources(),
634                                    files, testSourceDirectories );
635             }
636         }
637         else
638         {
639             Collection<File> sourceDirectories = request.getSourceDirectories();
640             addFilesToProcess( request, sourceDirectories, request.getResources(),
641                 request.getTestResources(), files, request.getTestSourceDirectories() );
642         }
643 
644         getLogger().debug( "Added " + files.size() + " files to process." );
645 
646         return new ArrayList<>( files );
647     }
648 
649     private void addFilesToProcess( CheckstyleExecutorRequest request, Collection<File> sourceDirectories,
650                                     List<Resource> resources, List<Resource> testResources, Collection<File> files,
651                                     Collection<File> testSourceDirectories )
652         throws IOException
653     {
654         if ( sourceDirectories != null )
655         {
656             for ( File sourceDirectory : sourceDirectories )
657             {
658                 if ( sourceDirectory.isDirectory() )
659                 {
660                     final List<File> sourceFiles =
661                         FileUtils.getFiles( sourceDirectory, request.getIncludes(), request.getExcludes() );
662                     files.addAll( sourceFiles );
663                     getLogger().debug( "Added " + sourceFiles.size() + " source files found in '"
664                                            + sourceDirectory.getAbsolutePath() + "'." );
665                 }
666             }
667         }
668 
669         if ( request.isIncludeTestSourceDirectory() && testSourceDirectories != null )
670         {
671             for ( File testSourceDirectory : testSourceDirectories )
672             {
673                 if ( testSourceDirectory.isDirectory() )
674                 {
675                     final List<File> testSourceFiles =
676                         FileUtils.getFiles( testSourceDirectory, request.getIncludes(), request.getExcludes() );
677                     
678                     files.addAll( testSourceFiles );
679                     getLogger().debug( "Added " + testSourceFiles.size() + " test source files found in '"
680                             + testSourceDirectory.getAbsolutePath() + "'." );
681                 }
682             }
683         }
684 
685         if ( resources != null && request.isIncludeResources() )
686         {
687             addResourceFilesToProcess( request, resources, files );
688         }
689         else
690         {
691             getLogger().debug( "No resources found in this project." );
692         }
693 
694         if ( testResources != null && request.isIncludeTestResources() )
695         {
696             addResourceFilesToProcess( request, testResources, files );
697         }
698         else
699         {
700             getLogger().debug( "No test resources found in this project." );
701         }
702     }
703 
704     private void addResourceFilesToProcess( CheckstyleExecutorRequest request, List<Resource> resources,
705                                             Collection<File> files )
706         throws IOException
707     {
708         for ( Resource resource : resources )
709         {
710             if ( resource.getDirectory() != null )
711             {
712                 File resourcesDirectory = new File( resource.getDirectory() );
713                 if ( resourcesDirectory.isDirectory() )
714                 {
715                     String includes = request.getResourceIncludes();
716                     String excludes = request.getResourceExcludes();
717 
718                     // MCHECKSTYLE-214: Only with project-root respect in/excludes, otherwise you'll get every file
719                     if ( resourcesDirectory.equals( request.getProject().getBasedir() ) )
720                     {
721                         String resourceIncludes = StringUtils.join( resource.getIncludes().iterator(), "," );
722                         if ( StringUtils.isEmpty( includes ) )
723                         {
724                             includes = resourceIncludes;
725                         }
726                         else
727                         {
728                             includes += "," + resourceIncludes;
729                         }
730                         
731                         String resourceExcludes = StringUtils.join( resource.getExcludes().iterator(), "," );
732                         if ( StringUtils.isEmpty( excludes ) )
733                         {
734                             excludes = resourceExcludes;
735                         }
736                         else
737                         {
738                             excludes += "," + resourceExcludes;
739                         }
740                     }
741                     
742                     List<File> resourceFiles =
743                         FileUtils.getFiles( resourcesDirectory, includes, excludes );
744                     files.addAll( resourceFiles );
745                     getLogger().debug( "Added " + resourceFiles.size() + " resource files found in '"
746                             + resourcesDirectory.getAbsolutePath() + "'." );
747                 }
748                 else
749                 {
750                     getLogger().debug( "The resources directory '" + resourcesDirectory.getAbsolutePath()
751                             + "' does not exist or is not a directory." );
752                 }
753             }
754         }
755     }
756 
757     private FilterSet getSuppressionsFilterSet( final String suppressionsFilePath )
758         throws CheckstyleExecutorException
759     {
760         if ( suppressionsFilePath == null )
761         {
762             return null;
763         }
764 
765         try
766         {
767             return SuppressionsLoader.loadSuppressions( suppressionsFilePath );
768         }
769         catch ( CheckstyleException ce )
770         {
771             throw new CheckstyleExecutorException( "Failed to load suppressions file from: "
772                 + suppressionsFilePath, ce );
773         }
774     }
775 
776     private String getSuppressionsFilePath( final CheckstyleExecutorRequest request )
777         throws CheckstyleExecutorException
778     {
779         final String suppressionsLocation = request.getSuppressionsLocation();
780         if ( StringUtils.isEmpty( suppressionsLocation ) )
781         {
782             return null;
783         }
784         
785         try
786         {
787             File suppressionsFile = locator.getResourceAsFile( suppressionsLocation, "checkstyle-suppressions.xml" );
788             return suppressionsFile == null ? null : suppressionsFile.getAbsolutePath();
789         }
790         catch ( ResourceNotFoundException e )
791         {
792             throw new CheckstyleExecutorException( "Unable to find suppressions file at location: "
793                 + suppressionsLocation, e );
794         }
795         catch ( FileResourceCreationException e )
796         {
797             throw new CheckstyleExecutorException( "Unable to process suppressions file location: "
798                 + suppressionsLocation, e );
799         }
800     }
801 
802     private String getConfigFile( CheckstyleExecutorRequest request )
803         throws CheckstyleExecutorException
804     {
805         try
806         {
807             if ( getLogger().isDebugEnabled() )
808             {
809                 getLogger().debug( "request.getConfigLocation() " + request.getConfigLocation() );
810             }
811 
812             File configFile = locator.getResourceAsFile( request.getConfigLocation(), "checkstyle-checker.xml" );
813             if ( configFile == null )
814             {
815                 throw new CheckstyleExecutorException( "Unable to process config location: "
816                     + request.getConfigLocation() );
817             }
818             return configFile.getAbsolutePath();
819         }
820         catch ( ResourceNotFoundException e )
821         {
822             throw new CheckstyleExecutorException( "Unable to find configuration file at location: "
823                 + request.getConfigLocation(), e );
824         }
825         catch ( FileResourceCreationException e )
826         {
827             throw new CheckstyleExecutorException( "Unable to process configuration file at location: "
828                 + request.getConfigLocation(), e );
829         }
830 
831     }
832 
833     /**
834      * Configures search paths in the resource locator.
835      * This method should only be called once per execution.
836      *
837      * @param request executor request data.
838      */
839     private void configureResourceLocator( final ResourceManager resourceManager,
840                                            final CheckstyleExecutorRequest request,
841                                            final List<Artifact> additionalArtifacts )
842     {
843         final MavenProject project = request.getProject();
844         resourceManager.setOutputDirectory( new File( project.getBuild().getDirectory() ) );
845 
846         // Recurse up the parent hierarchy and add project directories to the search roots
847         MavenProject parent = project;
848         while ( parent != null && parent.getFile() != null )
849         {
850             // MCHECKSTYLE-131 ( olamy ) I don't like this hack.
851             // (dkulp) Me either.   It really pollutes the location stuff
852             // by allowing searches of stuff outside the current module.
853             File dir = parent.getFile().getParentFile();
854             resourceManager.addSearchPath( FileResourceLoader.ID, dir.getAbsolutePath() );
855             parent = parent.getParent();
856         }
857         resourceManager.addSearchPath( "url", "" );
858         
859         // MCHECKSTYLE-225: load licenses from additional artifacts, not from classpath
860         if ( additionalArtifacts != null )
861         {
862             for ( Artifact licenseArtifact : additionalArtifacts )
863             {
864                 try
865                 {
866                     resourceManager.addSearchPath( "jar", "jar:" + licenseArtifact.getFile().toURI().toURL() );
867                 }
868                 catch ( MalformedURLException e )
869                 {
870                     // noop
871                 }
872             }
873         }
874     }
875 }