1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin.checkstyle;
20
21 import java.io.ByteArrayInputStream;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.IOException;
25 import java.net.MalformedURLException;
26 import java.net.URL;
27 import java.net.URLClassLoader;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.List;
31 import java.util.Properties;
32
33 import org.apache.maven.artifact.DependencyResolutionRequiredException;
34 import org.apache.maven.project.MavenProject;
35 import org.codehaus.plexus.logging.AbstractLogEnabled;
36 import org.codehaus.plexus.resource.ResourceManager;
37 import org.codehaus.plexus.resource.loader.FileResourceCreationException;
38 import org.codehaus.plexus.resource.loader.FileResourceLoader;
39 import org.codehaus.plexus.resource.loader.ResourceNotFoundException;
40 import org.codehaus.plexus.util.FileUtils;
41 import org.codehaus.plexus.util.StringUtils;
42
43 import com.puppycrawl.tools.checkstyle.Checker;
44 import com.puppycrawl.tools.checkstyle.ConfigurationLoader;
45 import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
46 import com.puppycrawl.tools.checkstyle.PackageNamesLoader;
47 import com.puppycrawl.tools.checkstyle.PropertiesExpander;
48 import com.puppycrawl.tools.checkstyle.api.AuditListener;
49 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
50 import com.puppycrawl.tools.checkstyle.api.Configuration;
51 import com.puppycrawl.tools.checkstyle.api.FilterSet;
52 import com.puppycrawl.tools.checkstyle.filters.SuppressionsLoader;
53
54
55
56
57
58
59
60 public class DefaultCheckstyleExecutor
61 extends AbstractLogEnabled
62 implements CheckstyleExecutor
63 {
64
65
66
67
68 private ResourceManager locator;
69
70 private static final File[] EMPTY_FILE_ARRAY = new File[0];
71
72 public CheckstyleResults executeCheckstyle( CheckstyleExecutorRequest request )
73 throws CheckstyleExecutorException, CheckstyleException
74 {
75
76
77
78
79 ClassLoader checkstyleClassLoader = PackageNamesLoader.class.getClassLoader();
80 Thread.currentThread().setContextClassLoader( checkstyleClassLoader );
81
82 if ( getLogger().isDebugEnabled() )
83 {
84 getLogger().debug( "executeCheckstyle start headerLocation : " + request.getHeaderLocation() );
85 }
86 locator.setOutputDirectory( new File( request.getProject().getBuild().getDirectory() ) );
87 File[] files;
88 try
89 {
90 files = getFilesToProcess( request );
91 }
92 catch ( IOException e )
93 {
94 throw new CheckstyleExecutorException( "Error getting files to process", e );
95 }
96
97 FilterSet filterSet = getSuppressions( request );
98
99 Checker checker = new Checker();
100
101
102
103 List<String> classPathStrings = new ArrayList<String>();
104 List<String> outputDirectories = new ArrayList<String>();
105 try
106 {
107 classPathStrings = request.getProject().getCompileClasspathElements();
108 outputDirectories.add( request.getProject().getBuild().getOutputDirectory() );
109
110 if ( request.isIncludeTestSourceDirectory() && ( request.getSourceDirectory() != null )
111 && ( request.getTestSourceDirectory().exists() ) && ( request.getTestSourceDirectory().isDirectory() ) )
112 {
113 classPathStrings = request.getProject().getTestClasspathElements();
114 outputDirectories.add( request.getProject().getBuild().getTestOutputDirectory() );
115 }
116 }
117 catch ( DependencyResolutionRequiredException e )
118 {
119 throw new CheckstyleExecutorException( e.getMessage(), e );
120 }
121
122 if ( classPathStrings == null )
123 {
124 classPathStrings = Collections.EMPTY_LIST;
125 }
126
127 List<URL> urls = new ArrayList<URL>( classPathStrings.size() );
128
129 for ( String path : classPathStrings )
130 {
131 try
132 {
133 urls.add( new File( path ).toURL() );
134 }
135 catch ( MalformedURLException e )
136 {
137 throw new CheckstyleExecutorException( e.getMessage(), e );
138 }
139 }
140
141 for ( String outputDirectoryString : outputDirectories )
142 {
143 try
144 {
145 if ( outputDirectoryString != null )
146 {
147 File outputDirectoryFile = new File( outputDirectoryString );
148 if ( outputDirectoryFile.exists() )
149 {
150 URL outputDirectoryUrl = outputDirectoryFile.toURL();
151 request.getLog().debug(
152 "Adding the outputDirectory " + outputDirectoryUrl.toString()
153 + " to the Checkstyle class path" );
154 urls.add( outputDirectoryUrl );
155 }
156 }
157 }
158 catch ( MalformedURLException e )
159 {
160 throw new CheckstyleExecutorException( e.getMessage(), e );
161 }
162 }
163
164 URLClassLoader projectClassLoader = new URLClassLoader( (URL[]) urls.toArray( new URL[urls.size()] ), null );
165 checker.setClassloader( projectClassLoader );
166
167 checker.setModuleClassLoader( Thread.currentThread().getContextClassLoader() );
168
169 if ( filterSet != null )
170 {
171 checker.addFilter( filterSet );
172 }
173 Configuration configuration = getConfiguration( request );
174 checker.configure( configuration );
175
176 AuditListener listener = request.getListener();
177
178 if ( listener != null )
179 {
180 checker.addListener( listener );
181 }
182
183 if ( request.isConsoleOutput() )
184 {
185 checker.addListener( request.getConsoleListener() );
186 }
187
188 CheckstyleReportListener sinkListener = new CheckstyleReportListener( request.getSourceDirectory(), configuration );
189 if ( request.isIncludeTestSourceDirectory() && ( request.getTestSourceDirectory() != null )
190 && ( request.getTestSourceDirectory().exists() ) && ( request.getTestSourceDirectory().isDirectory() ) )
191 {
192 sinkListener.addSourceDirectory( request.getTestSourceDirectory() );
193 }
194
195 checker.addListener( sinkListener );
196
197 List<File> filesList = new ArrayList<File>();
198 for ( int i = 0; i < files.length; i++ )
199 {
200 filesList.add( files[i] );
201 }
202 int nbErrors = checker.process( filesList );
203
204 checker.destroy();
205
206 if ( request.getStringOutputStream() != null )
207 {
208 request.getLog().info( request.getStringOutputStream().toString() );
209 }
210
211 if ( request.isFailsOnError() && nbErrors > 0 )
212 {
213
214
215
216 throw new CheckstyleExecutorException( "There are " + nbErrors + " checkstyle errors." );
217 }
218 else if ( nbErrors > 0 )
219 {
220 request.getLog().info( "There are " + nbErrors + " checkstyle errors." );
221 }
222
223 return sinkListener.getResults();
224 }
225
226 public Configuration getConfiguration( CheckstyleExecutorRequest request )
227 throws CheckstyleExecutorException
228 {
229 try
230 {
231
232
233
234 ClassLoader checkstyleClassLoader = PackageNamesLoader.class.getClassLoader();
235 Thread.currentThread().setContextClassLoader( checkstyleClassLoader );
236 String configFile = getConfigFile( request );
237 Properties overridingProperties = getOverridingProperties( request );
238 Configuration config = ConfigurationLoader
239 .loadConfiguration( configFile, new PropertiesExpander( overridingProperties ) );
240 String effectiveEncoding = StringUtils.isNotEmpty( request.getEncoding() ) ? request.getEncoding() : System
241 .getProperty( "file.encoding", "UTF-8" );
242 if ( StringUtils.isEmpty( request.getEncoding() ) )
243 {
244 request.getLog().warn(
245 "File encoding has not been set, using platform encoding " + effectiveEncoding
246 + ", i.e. build is platform dependent!" );
247 }
248 Configuration[] modules = config.getChildren();
249 for ( int i = 0; i < modules.length; i++ )
250 {
251 Configuration module = modules[i];
252 if ( "Checker".equals( module.getName() )
253 || "com.puppycrawl.tools.checkstyle.Checker".equals( module.getName() ) )
254 {
255 if ( module instanceof DefaultConfiguration )
256 {
257 ( (DefaultConfiguration) module ).addAttribute( "charset", effectiveEncoding );
258 }
259 else
260 {
261 request.getLog().warn( "Failed to configure file encoding on module " + module );
262 }
263 }
264 if ( "TreeWalker".equals( module.getName() )
265 || "com.puppycrawl.tools.checkstyle.TreeWalker".equals( module.getName() ) )
266 {
267 if ( module instanceof DefaultConfiguration )
268 {
269 ( (DefaultConfiguration) module ).addAttribute( "cacheFile", request.getCacheFile() );
270 }
271 else
272 {
273 request.getLog().warn( "Failed to configure cache file on module " + module );
274 }
275 }
276 }
277 return config;
278 }
279 catch ( CheckstyleException e )
280 {
281 throw new CheckstyleExecutorException( "Failed during checkstyle configuration", e );
282 }
283 }
284
285 private Properties getOverridingProperties( CheckstyleExecutorRequest request )
286 throws CheckstyleExecutorException
287 {
288 Properties p = new Properties();
289
290 try
291 {
292 if ( request.getPropertiesLocation() != null )
293 {
294 if ( getLogger().isDebugEnabled() )
295 {
296 getLogger().debug( "request.getPropertiesLocation() " + request.getPropertiesLocation() );
297 }
298
299 File propertiesFile = locator.getResourceAsFile( request.getPropertiesLocation(),
300 "checkstyle-checker.properties" );
301
302 if ( propertiesFile != null )
303 {
304 p.load( new FileInputStream( propertiesFile ) );
305 }
306 }
307
308 if ( StringUtils.isNotEmpty( request.getPropertyExpansion() ) )
309 {
310 String propertyExpansion = request.getPropertyExpansion();
311
312 propertyExpansion = StringUtils.replace( propertyExpansion, "\\", "\\\\" );
313 p.load( new ByteArrayInputStream( propertyExpansion.getBytes() ) );
314 }
315
316
317
318
319 String headerLocation = request.getHeaderLocation();
320 if ( "config/maven_checks.xml".equals( request.getConfigLocation() ) )
321 {
322
323 if ( "LICENSE.txt".equals( request.getHeaderLocation() ) )
324 {
325 headerLocation = "config/maven-header.txt";
326 }
327 }
328 if ( getLogger().isDebugEnabled() )
329 {
330 getLogger().debug( "headerLocation " + headerLocation );
331 }
332
333 if ( StringUtils.isNotEmpty( headerLocation ) )
334 {
335 try
336 {
337 File headerFile = locator.getResourceAsFile( headerLocation, "checkstyle-header.txt" );
338
339 if ( headerFile != null )
340 {
341 p.setProperty( "checkstyle.header.file", headerFile.getAbsolutePath() );
342 }
343 }
344 catch ( FileResourceCreationException e )
345 {
346 throw new CheckstyleExecutorException( "Unable to process header location: " + headerLocation, e );
347 }
348 catch ( ResourceNotFoundException e )
349 {
350 throw new CheckstyleExecutorException( "Unable to process header location: " + headerLocation, e );
351 }
352 }
353
354 if ( request.getCacheFile() != null )
355 {
356 p.setProperty( "checkstyle.cache.file", request.getCacheFile() );
357 }
358 }
359 catch ( IOException e )
360 {
361 throw new CheckstyleExecutorException( "Failed to get overriding properties", e );
362 }
363 catch ( FileResourceCreationException e )
364 {
365 throw new CheckstyleExecutorException( "Failed to get overriding properties", e );
366 }
367 catch ( ResourceNotFoundException e )
368 {
369 throw new CheckstyleExecutorException( "Failed to get overriding properties", e );
370 }
371 if ( request.getSuppressionsFileExpression() != null )
372 {
373 String suppresionFile = request.getSuppressionsFileExpression();
374
375 if ( suppresionFile != null )
376 {
377 p.setProperty( request.getSuppressionsFileExpression(), suppresionFile );
378 }
379 }
380
381 return p;
382 }
383
384 private File[] getFilesToProcess( CheckstyleExecutorRequest request )
385 throws IOException
386 {
387 StringBuffer excludesStr = new StringBuffer();
388
389 if ( StringUtils.isNotEmpty( request.getExcludes() ) )
390 {
391 excludesStr.append( request.getExcludes() );
392 }
393
394 String[] defaultExcludes = FileUtils.getDefaultExcludes();
395 for ( int i = 0; i < defaultExcludes.length; i++ )
396 {
397 if ( excludesStr.length() > 0 )
398 {
399 excludesStr.append( "," );
400 }
401
402 excludesStr.append( defaultExcludes[i] );
403 }
404
405 if (request.getSourceDirectory() == null || !request.getSourceDirectory().exists())
406 {
407 return EMPTY_FILE_ARRAY;
408 }
409
410 List<File> files =
411 FileUtils.getFiles( request.getSourceDirectory(), request.getIncludes(), excludesStr.toString() );
412 if ( request.isIncludeTestSourceDirectory() && ( request.getTestSourceDirectory() != null )
413 && ( request.getTestSourceDirectory().exists() ) && ( request.getTestSourceDirectory().isDirectory() ) )
414 {
415 files.addAll( FileUtils.getFiles( request.getTestSourceDirectory(), request.getIncludes(),
416 excludesStr.toString() ) );
417 }
418
419 return (File[]) files.toArray( EMPTY_FILE_ARRAY );
420 }
421
422 private FilterSet getSuppressions( CheckstyleExecutorRequest request )
423 throws CheckstyleExecutorException
424 {
425 try
426 {
427 File suppressionsFile = locator.resolveLocation( request.getSuppressionsLocation(),
428 "checkstyle-suppressions.xml" );
429
430 if ( suppressionsFile == null )
431 {
432 return null;
433 }
434
435 return SuppressionsLoader.loadSuppressions( suppressionsFile.getAbsolutePath() );
436 }
437 catch ( CheckstyleException ce )
438 {
439 throw new CheckstyleExecutorException( "failed to load suppressions location: "
440 + request.getSuppressionsLocation(), ce );
441 }
442 catch ( IOException e )
443 {
444 throw new CheckstyleExecutorException( "Failed to process supressions location: "
445 + request.getSuppressionsLocation(), e );
446 }
447 }
448
449 private String getConfigFile( CheckstyleExecutorRequest request )
450 throws CheckstyleExecutorException
451 {
452 try
453 {
454 if ( getLogger().isDebugEnabled() )
455 {
456 getLogger().debug( "request.getConfigLocation() " + request.getConfigLocation() );
457 }
458
459 MavenProject parent = request.getProject();
460 while ( parent != null && parent.getFile() != null )
461 {
462
463
464
465 File dir = parent.getFile().getParentFile();
466 locator.addSearchPath( FileResourceLoader.ID, dir.getAbsolutePath() );
467 parent = parent.getParent();
468 }
469 locator.addSearchPath( "url", "" );
470
471 File configFile = locator.getResourceAsFile( request.getConfigLocation(), "checkstyle-checker.xml" );
472 if ( configFile == null )
473 {
474 throw new CheckstyleExecutorException( "Unable to process config location: "
475 + request.getConfigLocation() );
476 }
477 return configFile.getAbsolutePath();
478 }
479 catch ( org.codehaus.plexus.resource.loader.ResourceNotFoundException e )
480 {
481 throw new CheckstyleExecutorException( "Unable to find configuration file at location "
482 + request.getConfigLocation(), e );
483 }
484 catch ( FileResourceCreationException e )
485 {
486 throw new CheckstyleExecutorException( "Unable to process configuration file location "
487 + request.getConfigLocation(), e );
488 }
489
490 }
491 }