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