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