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