View Javadoc

1   ////////////////////////////////////////////////////////////////////////////////
2   //
3   //                  ObjectLab is sponsoring QALab
4   //
5   // Based in London, we are world leaders in the design and development
6   // of bespoke applications for the Securities Financing markets.
7   //
8   // <a href="http://www.objectlab.co.uk/open">Click here to learn more</a>
9   //           ___  _     _           _   _          _
10  //          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
11  //         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
12  //         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
13  //          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
14  //                   |__/
15  //
16  //                   http://www.ObjectLab.co.uk
17  // ---------------------------------------------------------------------------
18  //
19  //QALab is released under the GNU General Public License.
20  //
21  //QALab: Collects QA Statistics from your build over time.
22  //2005+, ObjectLab Ltd
23  //
24  //This library is free software; you can redistribute it and/or
25  //modify it under the terms of the GNU General Public
26  //License as published by the Free Software Foundation; either
27  //version 2.1 of the License, or (at your option) any later version.
28  //
29  //This library is distributed in the hope that it will be useful,
30  //but WITHOUT ANY WARRANTY; without even the implied warranty of
31  //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
32  //General Public License for more details.
33  //
34  //You should have received a copy of the GNU General Public
35  //License along with this library; if not, write to the Free Software
36  //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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      // ~ Instance fields -------------------------------------------------------
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     // ~ Methods
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         // If there was nothing to merge, create an empty qalab.xml in order to avoid reporting problems
246         // For instance, an empty qalab.xml is necessary for the root POM, when using <packaging>pom</packaging
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         // validate the provided parameters
265         if (!validate(inputFile)) {
266             return;
267         }
268 
269         // Display the files being processed
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             // create the exporter
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         // Load the properties file if specified
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         // override with Maven properties as apropriate.
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  *                   ObjectLab is sponsoring QALab
670  * 
671  * Based in London, we are world leaders in the design and development 
672  * of bespoke applications for the securities financing markets.
673  * 
674  * <a href="http://www.objectlab.co.uk/open">Click here to learn more about us</a>
675  *           ___  _     _           _   _          _
676  *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
677  *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
678  *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
679  *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
680  *                   |__/
681  *
682  *                     www.ObjectLab.co.uk
683  */