1 package org.apache.maven.plugin.checkstyle;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.BufferedReader;
23 import java.io.ByteArrayOutputStream;
24 import java.io.File;
25 import java.io.FileNotFoundException;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.OutputStream;
29 import java.io.Reader;
30
31 import org.apache.maven.plugin.AbstractMojo;
32 import org.apache.maven.plugin.MojoExecutionException;
33 import org.apache.maven.plugin.MojoFailureException;
34 import org.apache.maven.project.MavenProject;
35 import org.codehaus.plexus.resource.ResourceManager;
36 import org.codehaus.plexus.resource.loader.FileResourceLoader;
37 import org.codehaus.plexus.util.ReaderFactory;
38 import org.codehaus.plexus.util.StringUtils;
39 import org.codehaus.plexus.util.xml.pull.MXParser;
40 import org.codehaus.plexus.util.xml.pull.XmlPullParser;
41 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
42
43 import com.puppycrawl.tools.checkstyle.DefaultLogger;
44 import com.puppycrawl.tools.checkstyle.XMLLogger;
45 import com.puppycrawl.tools.checkstyle.api.AuditListener;
46 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
47
48
49
50
51
52
53
54
55
56
57
58
59 public class CheckstyleViolationCheckMojo
60 extends AbstractMojo
61 {
62
63
64
65
66
67
68
69
70 private File outputFile;
71
72
73
74
75
76
77
78 private String outputFileFormat;
79
80
81
82
83
84
85
86 private boolean failOnViolation;
87
88
89
90
91
92
93
94
95 private int maxAllowedViolations = 0;
96
97
98
99
100
101
102
103
104 private String violationSeverity = "error";
105
106
107
108
109
110
111
112 private boolean skip;
113
114
115
116
117
118
119
120 private boolean skipExec;
121
122
123
124
125
126
127
128 private boolean logViolationsToConsole;
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164 private String configLocation;
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188 private String propertiesLocation;
189
190
191
192
193
194
195 private String propertyExpansion;
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222 private String headerLocation;
223
224
225
226
227
228
229 private String cacheFile;
230
231
232
233
234
235
236
237
238 private String suppressionsFileExpression;
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260 private String suppressionsLocation;
261
262
263
264
265
266
267
268
269
270 private String encoding;
271
272
273
274
275
276
277
278 protected ResourceManager locator;
279
280
281
282
283
284
285
286 protected CheckstyleExecutor checkstyleExecutor;
287
288
289
290
291
292
293 private boolean consoleOutput;
294
295
296
297
298
299
300
301
302 protected MavenProject project;
303
304
305
306
307
308
309
310 private File useFile;
311
312
313
314
315
316
317
318 private String excludes;
319
320
321
322
323
324
325
326 private String includes;
327
328
329
330
331
332
333 private boolean failsOnError;
334
335
336
337
338
339
340
341
342 private File testSourceDirectory;
343
344
345
346
347
348
349
350 private boolean includeTestSourceDirectory;
351
352
353
354
355
356
357
358 private File sourceDirectory;
359
360 private ByteArrayOutputStream stringOutputStream;
361
362
363
364 public void execute()
365 throws MojoExecutionException, MojoFailureException
366 {
367
368 if ( !skip )
369 {
370
371 if ( !skipExec )
372 {
373 locator.addSearchPath( FileResourceLoader.ID, project.getFile().getParentFile().getAbsolutePath() );
374 locator.addSearchPath( "url", "" );
375
376 locator.setOutputDirectory( new File( project.getBuild().getDirectory() ) );
377
378 ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
379
380 try
381 {
382 CheckstyleExecutorRequest request = new CheckstyleExecutorRequest();
383 request.setConsoleListener( getConsoleListener() ).setConsoleOutput( consoleOutput )
384 .setExcludes( excludes ).setFailsOnError( failsOnError ).setIncludes( includes )
385 .setIncludeTestSourceDirectory( includeTestSourceDirectory ).setListener( getListener() )
386 .setLog( getLog() ).setProject( project ).setSourceDirectory( sourceDirectory )
387 .setStringOutputStream( stringOutputStream ).setSuppressionsLocation( suppressionsLocation )
388 .setTestSourceDirectory( testSourceDirectory ).setConfigLocation( configLocation )
389 .setPropertyExpansion( propertyExpansion ).setHeaderLocation( headerLocation )
390 .setCacheFile( cacheFile ).setSuppressionsFileExpression( suppressionsFileExpression )
391 .setEncoding( encoding ).setPropertiesLocation( propertiesLocation );
392
393 checkstyleExecutor.executeCheckstyle( request );
394
395 }
396 catch ( CheckstyleException e )
397 {
398 throw new MojoExecutionException( "Failed during checkstyle configuration", e );
399 }
400 catch ( CheckstyleExecutorException e )
401 {
402 throw new MojoExecutionException( "Failed during checkstyle execution", e );
403 }
404 finally
405 {
406
407 Thread.currentThread().setContextClassLoader( currentClassLoader );
408 }
409
410 }
411 if ( !"xml".equals( outputFileFormat ) )
412 {
413 throw new MojoExecutionException( "Output format is '" + outputFileFormat
414 + "', checkstyle:check requires format to be 'xml'." );
415 }
416
417 if ( !outputFile.exists() )
418 {
419 getLog().info(
420 "Unable to perform checkstyle:check, "
421 + "unable to find checkstyle:checkstyle outputFile." );
422 return;
423 }
424
425 try
426 {
427 XmlPullParser xpp = new MXParser();
428 Reader freader = ReaderFactory.newXmlReader( outputFile );
429 BufferedReader breader = new BufferedReader( freader );
430 xpp.setInput( breader );
431
432 int violations = countViolations( xpp );
433 if ( violations > maxAllowedViolations )
434 {
435 if ( failOnViolation )
436 {
437 String msg = "You have " + violations + " Checkstyle violation"
438 + ( ( violations > 1 ) ? "s" : "" ) + ".";
439 if ( maxAllowedViolations > 0 )
440 {
441 msg += " The maximum number of allowed violations is " + maxAllowedViolations + ".";
442 }
443 throw new MojoFailureException( msg );
444 }
445
446 getLog().warn( "checkstyle:check violations detected but failOnViolation set to false" );
447 }
448 }
449 catch ( IOException e )
450 {
451 throw new MojoExecutionException( "Unable to read Checkstyle results xml: "
452 + outputFile.getAbsolutePath(), e );
453 }
454 catch ( XmlPullParserException e )
455 {
456 throw new MojoExecutionException( "Unable to read Checkstyle results xml: "
457 + outputFile.getAbsolutePath(), e );
458 }
459 }
460 }
461
462 private int countViolations( XmlPullParser xpp )
463 throws XmlPullParserException, IOException
464 {
465 int count = 0;
466
467 int eventType = xpp.getEventType();
468 String file = "";
469 while ( eventType != XmlPullParser.END_DOCUMENT )
470 {
471 if ( eventType == XmlPullParser.START_TAG && "file".equals( xpp.getName() ) )
472 {
473 file = xpp.getAttributeValue( "", "name" );
474 file = file.substring( file.lastIndexOf( File.separatorChar ) + 1 );
475 }
476
477 if ( eventType == XmlPullParser.START_TAG && "error".equals( xpp.getName() )
478 && isViolation( xpp.getAttributeValue( "", "severity" ) ) )
479 {
480 if ( logViolationsToConsole )
481 {
482 StringBuffer stb = new StringBuffer();
483 stb.append( file );
484 stb.append( '[' );
485 stb.append( xpp.getAttributeValue( "", "line" ) );
486 stb.append( ':' );
487 stb.append( xpp.getAttributeValue( "", "column" ) );
488 stb.append( "] " );
489 stb.append( xpp.getAttributeValue( "", "message" ) );
490 getLog().error( stb.toString() );
491 }
492 count++;
493 }
494 eventType = xpp.next();
495 }
496
497 return count;
498 }
499
500
501
502
503
504
505
506 private boolean isViolation( String severity )
507 {
508 if ( "error".equals( severity ) )
509 {
510 return "error".equals( violationSeverity ) || "warning".equals( violationSeverity )
511 || "info".equals( violationSeverity );
512 }
513 else if ( "warning".equals( severity ) )
514 {
515 return "warning".equals( violationSeverity ) || "info".equals( violationSeverity );
516 }
517 else if ( "info".equals( severity ) )
518 {
519 return "info".equals( violationSeverity );
520 }
521 else
522 {
523 return false;
524 }
525 }
526 private DefaultLogger getConsoleListener()
527 throws MojoExecutionException
528 {
529 DefaultLogger consoleListener;
530
531 if ( useFile == null )
532 {
533 stringOutputStream = new ByteArrayOutputStream();
534 consoleListener = new DefaultLogger( stringOutputStream, false );
535 }
536 else
537 {
538 OutputStream out = getOutputStream( useFile );
539
540 consoleListener = new DefaultLogger( out, true );
541 }
542
543 return consoleListener;
544 }
545
546 private OutputStream getOutputStream( File file )
547 throws MojoExecutionException
548 {
549 File parentFile = file.getAbsoluteFile().getParentFile();
550
551 if ( !parentFile.exists() )
552 {
553 parentFile.mkdirs();
554 }
555
556 FileOutputStream fileOutputStream;
557 try
558 {
559 fileOutputStream = new FileOutputStream( file );
560 }
561 catch ( FileNotFoundException e )
562 {
563 throw new MojoExecutionException( "Unable to create output stream: " + file, e );
564 }
565 return fileOutputStream;
566 }
567
568 private AuditListener getListener()
569 throws MojoFailureException, MojoExecutionException
570 {
571 AuditListener listener = null;
572
573 if ( StringUtils.isNotEmpty( outputFileFormat ) )
574 {
575 File resultFile = outputFile;
576
577 OutputStream out = getOutputStream( resultFile );
578
579 if ( "xml".equals( outputFileFormat ) )
580 {
581 listener = new XMLLogger( out, true );
582 }
583 else if ( "plain".equals( outputFileFormat ) )
584 {
585 listener = new DefaultLogger( out, true );
586 }
587 else
588 {
589 throw new MojoFailureException( "Invalid output file format: (" + outputFileFormat
590 + "). Must be 'plain' or 'xml'." );
591 }
592 }
593
594 return listener;
595 }
596
597 }