1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 package net.objectlab.qalab.m2;
40
41 import org.apache.maven.plugin.AbstractMojo;
42 import org.apache.maven.plugin.MojoExecutionException;
43
44 import net.objectlab.qalab.interfaces.QALabExporter;
45 import net.objectlab.qalab.parser.StatMerger;
46 import net.objectlab.qalab.util.TaskLogger;
47 import net.objectlab.qalab.m2.util.Utils;
48 import net.objectlab.qalab.m2.util.Maven2TaskLogger;
49
50 import org.xml.sax.InputSource;
51
52 import java.io.File;
53 import java.io.FileInputStream;
54 import java.io.IOException;
55 import java.io.FileNotFoundException;
56
57 import java.util.Iterator;
58 import java.util.Map;
59 import java.util.Properties;
60
61 /**
62 * Use this goal to merge all available statistics, easiest use, supported:
63 * Checkstyle, PMD, PMD CPD, Simian, FindBugs, Cobertua Line and Cobertura
64 * Branch; it should not require any tailoring if you are using the Maven default
65 * for all those reports.
66 *
67 * @author Benoit Xhenseval
68 * @goal merge-all
69 * @phase site
70 */
71 public class QALabStatAllMergeMojo extends AbstractMojo {
72
73
74 /**
75 * The input file generated by Checkstyle.
76 *
77 * @parameter expression="${project.build.directory}/checkstyle-result.xml"
78 */
79 private File checkstyleInputFile = null;
80
81 /**
82 * The fully qualified class name for the handler for Checkstyle.
83 *
84 * @parameter default-value="net.objectlab.qalab.parser.CheckstyleStatMerge"
85 */
86 private String checkstyleHandler;
87
88 /**
89 * The input file generated by PMD.
90 *
91 * @parameter expression="${project.build.directory}/pmd.xml"
92 */
93 private File pmdInputFile = null;
94
95 /**
96 * The fully qualified class name for the handler for PMD.
97 *
98 * @parameter default-value="net.objectlab.qalab.parser.PMDStatMerge"
99 */
100 private String pmdHandler;
101
102 /**
103 * The input file generated by PMD CPD.
104 *
105 * @parameter expression="${project.build.directory}/cpd.xml"
106 */
107 private File pmdCpdInputFile = null;
108
109 /**
110 * The fully qualified class name for the handler for PMD CPD.
111 *
112 * @parameter default-value="net.objectlab.qalab.parser.PMDCPDStatMerge"
113 */
114 private String pmdCpdHandler;
115
116 /**
117 * The input file generated by FindBugs.
118 *
119 * @parameter expression="${project.build.directory}/findbugs.xml"
120 */
121 private File findbugsInputFile = null;
122
123 /**
124 * The fully qualified class name for the handler for FindBugs.
125 *
126 * @parameter default-value="net.objectlab.qalab.parser.FindBugsStatMerge"
127 */
128 private String findbugsHandler;
129
130 /**
131 * The input file generated by Simian.
132 *
133 * @parameter expression="${project.build.directory}/simian-raw-report.xml"
134 */
135 private File simianInputFile = null;
136
137 /**
138 * The fully qualified class name for the handler for Simian.
139 *
140 * @parameter default-value="net.objectlab.qalab.parser.SimianStatMerge"
141 */
142 private String simianHandler;
143
144 /**
145 * The input file generated by Cobertura.
146 *
147 * @parameter expression="${project.reporting.outputDirectory}/cobertura/coverage.xml"
148 */
149 private File coberturaInputFile = null;
150
151 /**
152 * The fully qualified class name for the handler for Cobertura Line.
153 *
154 * @parameter default-value="net.objectlab.qalab.parser.CoberturaLineStatMerge"
155 */
156 private String coberturaLineHandler;
157
158 /**
159 * The fully qualified class name for the handler for Cobertura Branch.
160 *
161 * @parameter default-value="net.objectlab.qalab.parser.CoberturaBranchStatMerge"
162 */
163 private String coberturaBranchHandler;
164
165 /**
166 * The merged properties file. By default this is generated into the root of
167 * the project as it is often checked into source control.
168 *
169 * @parameter expression="${project.basedir}/qalab.xml"
170 */
171 private File outputFile = null;
172
173 /**
174 * If true then any debug logging output will be suppressed.
175 *
176 * @parameter default-value=false
177 */
178 private boolean quiet = false;
179
180 /**
181 * If true then use ONLY DATE for timestamp (use in conjunction action
182 * replace).
183 *
184 * @parameter default-value=true
185 */
186 private boolean dateOnly = true;
187
188 /**
189 * The directory where the source code is.
190 *
191 * @parameter expression="${project.build.sourceDirectory}"
192 */
193 private String srcDir;
194
195 /**
196 * The timestamp for the stats.
197 *
198 * @parameter
199 */
200 private String mergerTimeStamp;
201
202 /**
203 * An exporter class name.
204 *
205 * @parameter default-value="net.objectlab.qalab.exporter.QALabXMLExporter"
206 */
207 private String exporterClassName = "net.objectlab.qalab.exporter.QALabXMLExporter";
208
209 /**
210 * The properties file to use instead of setting them one by one.
211 *
212 * @parameter
213 */
214 private File propertiesFile;
215
216 /**
217 * the loaded properties from the properties file declared above.
218 */
219 private Properties theProperties = null;
220
221
222
223 /**
224 * Method invoked by the Maven framework to execute the action associated with
225 * this task. This will validate the input parameters then merge the
226 * statistics.
227 *
228 * @throws MojoExecutionException
229 * if anything goes wrong.
230 */
231 public final void execute() throws MojoExecutionException {
232
233 theProperties = createOverridingProperties();
234
235 getLog().info("Starting QALab ALL Merge");
236
237 doMerge(checkstyleInputFile, checkstyleHandler);
238 doMerge(pmdInputFile, pmdHandler);
239 doMerge(pmdCpdInputFile, pmdCpdHandler);
240 doMerge(findbugsInputFile, findbugsHandler);
241 doMerge(simianInputFile, simianHandler);
242 doMerge(coberturaInputFile, coberturaLineHandler);
243 doMerge(coberturaInputFile, coberturaBranchHandler);
244
245
246
247 if (!getOutputFile().exists()) {
248 try {
249 QALabExporter exporter = (QALabExporter) Class.forName(getExporterClassName()).newInstance();
250
251 getTheProperties().setProperty("qalab.merge.output.file", getOutputFile().getAbsolutePath());
252 exporter.setQuiet(isQuiet());
253 exporter.setTaskLogger(new Maven2TaskLogger(this));
254 exporter.configure(getTheProperties());
255
256 exporter.save();
257 } catch (Exception excn) {
258 excn.printStackTrace();
259 }
260 }
261 }
262
263 private void doMerge(File inputFile, String handler) throws MojoExecutionException {
264
265 if (!validate(inputFile)) {
266 return;
267 }
268
269
270 if (!quiet) {
271 getLog().info("----------------------------------------------");
272 getLog().info("QALab Merge:");
273 getLog().info("checkstyleInputFile='" + inputFile.getPath());
274 getLog().info("outputFile='" + outputFile.getPath());
275 getLog().info("srcDir='" + srcDir + "', mergerTimeStamp=" + mergerTimeStamp);
276 String proppath = null;
277 if (propertiesFile != null) {
278 proppath = propertiesFile.getPath();
279 }
280 getLog().info("quiet='" + quiet + "', propertiesFile='" + proppath + "'.");
281 for (final Iterator it = theProperties.entrySet().iterator(); it.hasNext();) {
282
283 final Map.Entry entry = (Map.Entry) it.next();
284 final String key = entry.getKey().toString();
285 if (key.indexOf("qalab") >= 0) {
286 getLog().info(key + " = '" + entry.getValue() + "'");
287 }
288 }
289 }
290
291 mergeFiles(inputFile, handler);
292 }
293
294 /**
295 * Merge the statistics into the qalab.xml.
296 *
297 * @throws MojoExecutionException
298 * if anything goes wrong.
299 */
300 private void mergeFiles(File inputFile, String handler) throws MojoExecutionException {
301 try {
302 final TaskLogger logger = new Maven2TaskLogger(this);
303
304
305 final QALabExporter exporter = (QALabExporter) Class.forName(getExporterClassName()).newInstance();
306
307 getTheProperties().setProperty("qalab.merge.output.file", getOutputFile().getAbsolutePath());
308
309 exporter.setQuiet(isQuiet());
310 exporter.setTaskLogger(logger);
311
312 final StatMerger merger = (StatMerger) Class.forName(handler).newInstance();
313
314 merger.setQuiet(isQuiet());
315 merger.setSrcDir(getSrcDir());
316 merger.setTaskLogger(logger);
317 merger.setMergerTimeStamp(getMergerTimeStamp(), dateOnly);
318
319 getTheProperties().setProperty("qalab.merge.output.timestamp", merger.getMergerTimeStamp());
320 getTheProperties().setProperty("qalab.merge.type", merger.getType());
321 exporter.configure(getTheProperties());
322
323 merger.mergeStats(new InputSource(new FileInputStream(inputFile)), exporter);
324 getLog().info("Files: " + merger.getFileCount() + " Violations:" + merger.getTotalStatistics());
325
326 exporter.save();
327 } catch (IllegalAccessException e) {
328 throw new MojoExecutionException(e.toString());
329 } catch (FileNotFoundException e) {
330 throw new MojoExecutionException(e.toString());
331 } catch (IOException e) {
332 throw new MojoExecutionException(e.toString());
333 } catch (ClassNotFoundException e) {
334 throw new MojoExecutionException(e.toString());
335 } catch (InstantiationException e) {
336 throw new MojoExecutionException(e.toString());
337 }
338 }
339
340 /**
341 * Validates the parameters supplied by maven 2.
342 */
343 private boolean validate(final File file) {
344 try {
345 Utils.checkFile(file, "inputFile");
346 return true;
347 } catch (IOException ioex) {
348 getLog().warn("\n\nQALab ==> The file " + file.getPath() + " cannot be accessed. SKIPPING....\n\n");
349 }
350 return false;
351 }
352
353 /**
354 * Create the Properties object based on the arguments specified to the Mojo
355 * in your <code>pom.xml</code> file.
356 *
357 * @return the properties for property expansion expansion
358 * @throws MojoExecutionException
359 * if anything goes wrong.
360 */
361 private Properties createOverridingProperties() throws MojoExecutionException {
362
363 final Properties result = new Properties();
364
365
366 if (propertiesFile != null && propertiesFile.canRead() && propertiesFile.isFile()) {
367 FileInputStream inStream = null;
368 if (!quiet) {
369 getLog().debug("loading " + propertiesFile);
370 }
371
372 try {
373 inStream = new FileInputStream(propertiesFile);
374 result.load(inStream);
375 } catch (FileNotFoundException fnfex) {
376 throw new MojoExecutionException("Could not find Properties file '" + propertiesFile + "'", fnfex);
377 } catch (IOException ioex) {
378 throw new MojoExecutionException("Error loading Properties file '" + propertiesFile + "'", ioex);
379 } finally {
380 try {
381 if (inStream != null) {
382 inStream.close();
383 }
384 } catch (IOException ioex) {
385 throw new MojoExecutionException("Error closing Properties file '" + propertiesFile + "'", ioex);
386 }
387 }
388 }
389
390
391 final Map projectContext = getPluginContext();
392
393 if (projectContext != null) {
394 for (final Iterator it = projectContext.entrySet().iterator(); it.hasNext();) {
395
396 final Map.Entry entry = (Map.Entry) it.next();
397 final String value = String.valueOf(entry.getValue());
398 if (entry.getKey().toString().indexOf("qalab") >= 0) {
399 getLog().info("Adding " + entry.getKey() + " / " + value);
400 }
401 result.put(entry.getKey(), value);
402 }
403 }
404
405 return result;
406 }
407
408 public String getExporterClassName() {
409 return exporterClassName;
410 }
411
412 public void setExporterClassName(String exporterClassName) {
413 this.exporterClassName = exporterClassName;
414 }
415
416 public File getInputFile() {
417 return checkstyleInputFile;
418 }
419
420 public void setInputFile(File inputFile) {
421 this.checkstyleInputFile = inputFile;
422 }
423
424 public String getMergerTimeStamp() {
425 return mergerTimeStamp;
426 }
427
428 public void setMergerTimeStamp(String mergerTimeStamp) {
429 this.mergerTimeStamp = mergerTimeStamp;
430 }
431
432 public File getOutputFile() {
433 return outputFile;
434 }
435
436 public void setOutputFile(File outputFile) {
437 this.outputFile = outputFile;
438 }
439
440 public File getPropertiesFile() {
441 return propertiesFile;
442 }
443
444 public void setPropertiesFile(File propertiesFile) {
445 this.propertiesFile = propertiesFile;
446 }
447
448 public boolean isQuiet() {
449 return quiet;
450 }
451
452 public void setQuiet(boolean quiet) {
453 this.quiet = quiet;
454 }
455
456 public String getSrcDir() {
457 return srcDir;
458 }
459
460 public void setSrcDir(String srcDir) {
461 this.srcDir = srcDir;
462 }
463
464 public Properties getTheProperties() {
465 return theProperties;
466 }
467
468 public void setTheProperties(Properties theProperties) {
469 this.theProperties = theProperties;
470 }
471
472 /**
473 * @return the checkstyleHandler
474 */
475 public String getCheckstyleHandler() {
476 return checkstyleHandler;
477 }
478
479 /**
480 * @param checkstyleHandler the checkstyleHandler to set
481 */
482 public void setCheckstyleHandler(String checkstyleHandler) {
483 this.checkstyleHandler = checkstyleHandler;
484 }
485
486 /**
487 * @return the checkstyleInputFile
488 */
489 public File getCheckstyleInputFile() {
490 return checkstyleInputFile;
491 }
492
493 /**
494 * @param checkstyleInputFile the checkstyleInputFile to set
495 */
496 public void setCheckstyleInputFile(File checkstyleInputFile) {
497 this.checkstyleInputFile = checkstyleInputFile;
498 }
499
500 /**
501 * @return the coberturaBranchHandler
502 */
503 public String getCoberturaBranchHandler() {
504 return coberturaBranchHandler;
505 }
506
507 /**
508 * @param coberturaBranchHandler the coberturaBranchHandler to set
509 */
510 public void setCoberturaBranchHandler(String coberturaBranchHandler) {
511 this.coberturaBranchHandler = coberturaBranchHandler;
512 }
513
514 /**
515 * @return the coberturaInputFile
516 */
517 public File getCoberturaInputFile() {
518 return coberturaInputFile;
519 }
520
521 /**
522 * @param coberturaInputFile the coberturaInputFile to set
523 */
524 public void setCoberturaInputFile(File coberturaInputFile) {
525 this.coberturaInputFile = coberturaInputFile;
526 }
527
528 /**
529 * @return the coberturaLineHandler
530 */
531 public String getCoberturaLineHandler() {
532 return coberturaLineHandler;
533 }
534
535 /**
536 * @param coberturaLineHandler the coberturaLineHandler to set
537 */
538 public void setCoberturaLineHandler(String coberturaLineHandler) {
539 this.coberturaLineHandler = coberturaLineHandler;
540 }
541
542 /**
543 * @return the dateOnly
544 */
545 public boolean isDateOnly() {
546 return dateOnly;
547 }
548
549 /**
550 * @param dateOnly the dateOnly to set
551 */
552 public void setDateOnly(boolean dateOnly) {
553 this.dateOnly = dateOnly;
554 }
555
556 /**
557 * @return the findbugsHandler
558 */
559 public String getFindbugsHandler() {
560 return findbugsHandler;
561 }
562
563 /**
564 * @param findbugsHandler the findbugsHandler to set
565 */
566 public void setFindbugsHandler(String findbugsHandler) {
567 this.findbugsHandler = findbugsHandler;
568 }
569
570 /**
571 * @return the findbugsInputFile
572 */
573 public File getFindbugsInputFile() {
574 return findbugsInputFile;
575 }
576
577 /**
578 * @param findbugsInputFile the findbugsInputFile to set
579 */
580 public void setFindbugsInputFile(File findbugsInputFile) {
581 this.findbugsInputFile = findbugsInputFile;
582 }
583
584 /**
585 * @return the pmdCpdHandler
586 */
587 public String getPmdCpdHandler() {
588 return pmdCpdHandler;
589 }
590
591 /**
592 * @param pmdCpdHandler the pmdCpdHandler to set
593 */
594 public void setPmdCpdHandler(String pmdCpdHandler) {
595 this.pmdCpdHandler = pmdCpdHandler;
596 }
597
598 /**
599 * @return the pmdCpdInputFile
600 */
601 public File getPmdCpdInputFile() {
602 return pmdCpdInputFile;
603 }
604
605 /**
606 * @param pmdCpdInputFile the pmdCpdInputFile to set
607 */
608 public void setPmdCpdInputFile(File pmdCpdInputFile) {
609 this.pmdCpdInputFile = pmdCpdInputFile;
610 }
611
612 /**
613 * @return the pmdHandler
614 */
615 public String getPmdHandler() {
616 return pmdHandler;
617 }
618
619 /**
620 * @param pmdHandler the pmdHandler to set
621 */
622 public void setPmdHandler(String pmdHandler) {
623 this.pmdHandler = pmdHandler;
624 }
625
626 /**
627 * @return the pmdInputFile
628 */
629 public File getPmdInputFile() {
630 return pmdInputFile;
631 }
632
633 /**
634 * @param pmdInputFile the pmdInputFile to set
635 */
636 public void setPmdInputFile(File pmdInputFile) {
637 this.pmdInputFile = pmdInputFile;
638 }
639
640 /**
641 * @return the simianHandler
642 */
643 public String getSimianHandler() {
644 return simianHandler;
645 }
646
647 /**
648 * @param simianHandler the simianHandler to set
649 */
650 public void setSimianHandler(String simianHandler) {
651 this.simianHandler = simianHandler;
652 }
653
654 /**
655 * @return the simianInputFile
656 */
657 public File getSimianInputFile() {
658 return simianInputFile;
659 }
660
661 /**
662 * @param simianInputFile the simianInputFile to set
663 */
664 public void setSimianInputFile(File simianInputFile) {
665 this.simianInputFile = simianInputFile;
666 }
667 }
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683