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