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