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.report;
40  
41  import java.io.File;
42  import java.io.IOException;
43  import java.util.Locale;
44  import java.util.Properties;
45  import java.util.ResourceBundle;
46  import java.io.FileInputStream;
47  import java.io.InputStream;
48  
49  import net.objectlab.qalab.m2.BuildStatChartMojo;
50  import net.objectlab.qalab.m2.QALabStatAllMergeMojo;
51  import net.objectlab.qalab.m2.util.Utils;
52  import net.objectlab.qalab.m2.util.XmlTransformer;
53  
54  import org.apache.maven.plugin.MojoExecutionException;
55  import org.apache.maven.project.MavenProject;
56  import org.apache.maven.reporting.AbstractMavenReport;
57  import org.apache.maven.reporting.MavenReportException;
58  
59  import org.codehaus.doxia.site.renderer.SiteRenderer;
60  import javax.xml.transform.TransformerException;
61  
62  /**
63   * *** IMPORTANT USE this Report as part of your reporting section, it merges the data in qalab.xml,
64   * creates the charts and generates the chart report, ensure that this report is run AFTER Checkstyle,
65   * pmd, Findbugs, Cobertura, etc.
66   *
67   * @author Benoit Xhenseval.
68   * @goal report-merge-chart
69   * @phase deploy
70   */
71  public class MergeAndChartReport extends AbstractMavenReport {
72  
73      // ~ MERGE 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      * If true then any debug logging output will be suppressed.
167      *
168      * @parameter default-value=false
169      */
170     private boolean quiet = false;
171 
172     /**
173      * If true then use ONLY DATE for timestamp (use in conjunction action
174      * replace).
175      *
176      * @parameter default-value=true
177      */
178     private boolean dateOnly = true;
179 
180     /**
181      * The directory where the source code is.
182      *
183      * @parameter expression="${project.build.sourceDirectory}"
184      */
185     private String srcDir;
186 
187     /**
188      * The timestamp for the stats.
189      *
190      * @parameter
191      */
192     private String mergerTimeStamp;
193 
194     /**
195      * An exporter class name.
196      *
197      * @parameter default-value="net.objectlab.qalab.exporter.QALabXMLExporter"
198      */
199     private String exporterClassName = "net.objectlab.qalab.exporter.QALabXMLExporter";
200 
201     /**
202      * The properties file to use instead of setting them one by one.
203      *
204      * @parameter
205      */
206     private File propertiesFile;
207 
208     /**
209      * the loaded properties from the properties file declared above.
210      */
211     private Properties theProperties = null;
212 
213     // -------------------- CHART GENERATION ------------------------------------------
214 
215     /**
216      * The directory where the generated html report will go.
217      *
218      * @parameter expression="${project.reporting.outputDirectory}/qalab"
219      * @required
220      */
221     private File chartOutputDirectory;
222 
223     /**
224      * The Chart chartWidth.
225      *
226      * @parameter default-value=750
227      */
228     private int chartWidth;
229 
230     /**
231      * The Chart chartHeight.
232      *
233      * @parameter default-value=500
234      */
235     private int chartHeight;
236 
237     /**
238      * If the movingAverage is &lt;= 0 then there is no moving average, otherwise
239      * it shows the average based on the last n points, where n is the value of
240      * this field.
241      *
242      * @parameter default-value=0
243      */
244     private int movingAverage = 0;
245 
246     /**
247      * If true then generate a summary chart only.
248      *
249      * @parameter default-value=false
250      */
251     private boolean chartSummaryOnly = false;
252 
253     /**
254      * Statistic type to appear on summary chart, defaulted to
255      * 'checkstyle,pmd,findbugs,simian,pmd-cpd'.
256      *
257      * @parameter default-value="checkstyle,pmd,findbugs,simian,pmd-cpd"
258      */
259     private String summaryTypes = "checkstyle,pmd,findbugs,simian,pmd-cpd";
260 
261     /**
262      * File prefix for the charts (e.g. cobertura-) Default empty.
263      *
264      * @parameter default-value=""
265      */
266     private String chartFilePrefix = "";
267 
268     /**
269      * X Axis Title
270      *
271      * @parameter default-value="Date"
272      */
273     private String xAxisTitle = "Date";
274 
275     /**
276      * Y Axis Title
277      *
278      * @parameter default-value="Violation Count / Coverage Percent"
279      */
280     private String yAxisTitle = "Violation Count / Coverage Percent";
281 
282     /**
283      * X Axis Title for Summary
284      *
285      * @parameter default-value="Date"
286      */
287     private String xAxisSummaryTitle = "Date";
288 
289     /**
290      * Y Axis Title for Summary
291      *
292      * @parameter default-value="Violation Count"
293      */
294     private String yAxisSummaryTitle = "Violation Count";
295 
296     // -------------------- CHART REPORT ------------------------------------------
297 
298     /**
299      * The generated qalab.xml file.
300      *
301      * @parameter expression="${project.basedir}/qalab.xml"
302      */
303     private File qalabFile = null;
304 
305     /**
306      * The xslt stylesheet bundled, either qalab-chart-xdoc.xsl or
307      * qalab-chart-html.xsl.
308      *
309      * @parameter default-value="qalab-chart-xdoc.xsl";
310      */
311     private String chartBundledXsl = null;
312 
313     /**
314      * The directory where the generated xdoc/html report will go.
315      *
316      * @parameter expression="${project.build.directory}/generated-site/xdoc/qalab/"
317      * @required
318      */
319     private String outputDirectory;
320 
321     /**
322      * Statistic types, defaulted to
323      * 'checkstyle,pmd,pmd-cpd,findbugs,simian,cobertura-line,cobertura-branch'.
324      *
325      * @parameter default-value="checkstyle,pmd,pmd-cpd,findbugs,simian,cobertura-line,cobertura-branch"
326      */
327     private String types = "checkstyle,pmd,pmd-cpd,findbugs,simian,cobertura-line,cobertura-branch";
328 
329     /**
330      * The xml input stream.
331      */
332     private InputStream theXmlStream = null;
333 
334     /**
335      * The xslt style sheet.
336      *
337      * @parameter
338      */
339     private File styleSheet = null;
340 
341     /**
342      * The xslt style sheet input stream.
343      */
344     private InputStream theStyleSheetStream = null;
345 
346     /**
347      * The number of hours to define the time window from now.
348      *
349      * @parameter default-value="48"
350      */
351     private String startTimeHoursOffset = "48";
352 
353     /**
354      * The string version of the actual date computed by the offset set above.
355      */
356     private String theOffset;
357 
358     /**
359      * Not sure what this is.
360      *
361      * @component
362      */
363     private SiteRenderer siteRenderer;
364 
365     /**
366      * The maven project.
367      *
368      * @parameter expression="${project}"
369      * @required
370      * @readonly
371      */
372     private MavenProject project;
373 
374     /**
375      * generate the actual report.
376      *
377      * @param aLocale
378      *            ignored.
379      * @throws MavenReportException
380      *             if anything goes wrong.
381      */
382     protected final void executeReport(final Locale aLocale) throws MavenReportException {
383 
384         getLog().info("QALab: Merge and Chart Report");
385 
386         try {
387             doMerge();
388         } catch (MojoExecutionException e) {
389             throw new MavenReportException("Issue during Merge", e);
390         }
391 
392         try {
393             doChart();
394         } catch (MojoExecutionException e) {
395             throw new MavenReportException("Issue during Chart", e);
396         }
397 
398         validate();
399 
400         getLog().info("Output Directory: " + getOutputDirectory());
401 
402         final File outdir = new File(getOutputDirectory());
403         if (!outdir.exists()) {
404             outdir.mkdirs();
405         }
406         assert outdir.isDirectory() : "the output directory was not a directory";
407 
408         final File output;
409         try {
410             output = File.createTempFile("qalab", null, outdir);
411             assert output != null : "the temp file is null.";
412 
413         } catch (IOException ioex) {
414             throw new MavenReportException("could not create temp file.", ioex);
415         }
416 
417         final XmlTransformer t = new XmlTransformer(theXmlStream, theStyleSheetStream, output);
418         t.addParameter("targetdir", getOutputDirectory());
419         t.addParameter("type", types);
420         t.addParameter("offset", theOffset);
421         try {
422             t.transform();
423         } catch (TransformerException tex) {
424             throw new MavenReportException("transformation failed.", tex);
425         }
426 
427         // clean up the temp file when the plugin is done.
428         output.deleteOnExit();
429     }
430 
431     private void doMerge() throws MojoExecutionException {
432         QALabStatAllMergeMojo mojo = new QALabStatAllMergeMojo();
433         mojo.setCheckstyleHandler(checkstyleHandler);
434         mojo.setCheckstyleInputFile(checkstyleInputFile);
435         mojo.setPmdCpdHandler(pmdCpdHandler);
436         mojo.setPmdCpdInputFile(pmdCpdInputFile);
437         mojo.setPmdHandler(pmdHandler);
438         mojo.setPmdInputFile(pmdInputFile);
439         mojo.setSimianHandler(simianHandler);
440         mojo.setSimianInputFile(simianInputFile);
441         mojo.setCoberturaBranchHandler(coberturaBranchHandler);
442         mojo.setCoberturaInputFile(coberturaInputFile);
443         mojo.setCoberturaLineHandler(coberturaLineHandler);
444         mojo.setDateOnly(dateOnly);
445         mojo.setExporterClassName(exporterClassName);
446         mojo.setFindbugsHandler(findbugsHandler);
447         mojo.setFindbugsInputFile(findbugsInputFile);
448         mojo.setMergerTimeStamp(mergerTimeStamp);
449         mojo.setOutputFile(qalabFile);
450         mojo.setPropertiesFile(propertiesFile);
451         mojo.setQuiet(quiet);
452         mojo.setSrcDir(srcDir);
453         mojo.setTheProperties(theProperties);
454         mojo.setPluginContext(getPluginContext());
455 
456         mojo.execute();
457     }
458 
459     private void doChart() throws MojoExecutionException {
460         BuildStatChartMojo mojo = new BuildStatChartMojo();
461         mojo.setFilePrefix(chartFilePrefix);
462         mojo.setSummaryOnly(chartSummaryOnly);
463         mojo.setSummaryTypes(summaryTypes);
464         mojo.setHeight(chartHeight);
465         mojo.setWidth(chartWidth);
466         mojo.setMovingAverage(movingAverage);
467         mojo.setQalabFile(qalabFile);
468         mojo.setQuiet(quiet);
469         mojo.setToDir(chartOutputDirectory);
470         mojo.setTypes(types);
471         mojo.setPluginContext(getPluginContext());
472         mojo.setXAxisSummaryTitle(xAxisSummaryTitle);
473         mojo.setXAxisTitle(xAxisTitle);
474         mojo.setYAxisSummaryTitle(yAxisSummaryTitle);
475         mojo.setYAxisTitle(yAxisTitle);
476 
477         mojo.execute();
478 
479         // now just the cobertura report.
480         mojo.setFilePrefix("cobertura-" + chartFilePrefix);
481         mojo.setSummaryOnly(true);
482         mojo.setSummaryTypes("cobertura-line,cobertura-branch");
483         mojo.setYAxisSummaryTitle("Coverage Percent");
484         mojo.execute();
485     }
486 
487     /**
488      * @return "qalab/index"
489      * @see org.apache.maven.reporting.MavenReport#getOutputName()
490      */
491     public final String getOutputName() {
492         return "qalab/index";
493     }
494 
495     /**
496      * @return The output directory as configured in your <code>pom.xml</code>.
497      * @see org.apache.maven.reporting.AbstractMavenReport#getOutputDirectory()
498      */
499     protected final String getOutputDirectory() {
500         return outputDirectory;
501     }
502 
503     /**
504      * @return The Maven Project itself. Used internally to get access to Config
505      *         params etc.
506      * @see org.apache.maven.reporting.AbstractMavenReport#getProject()
507      */
508     protected final MavenProject getProject() {
509         return project;
510     }
511 
512     /**
513      * @return a direct reference to the site renderer.
514      * @see org.apache.maven.reporting.AbstractMavenReport#getSiteRenderer()
515      */
516     protected final SiteRenderer getSiteRenderer() {
517         return siteRenderer;
518     }
519 
520     /**
521      * @param aLocale
522      *            The locale.
523      * @return The locale specific report name.
524      * @see org.apache.maven.reporting.MavenReport#getName(java.util.Locale)
525      */
526     public final String getName(final Locale aLocale) {
527         return getBundle(aLocale).getString("report.qalab.name");
528     }
529 
530     /**
531      * @param aLocale
532      *            The locale.
533      * @return The locale specific report description.
534      * @see org.apache.maven.reporting.MavenReport#getDescription(java.util.Locale)
535      */
536     public final String getDescription(final Locale aLocale) {
537         return getBundle(aLocale).getString("report.qalab.description");
538     }
539 
540     /**
541      * @return true.
542      * @see org.apache.maven.reporting.MavenReport#isExternalReport
543      */
544     public final boolean isExternalReport() {
545         return true;
546     }
547 
548     /**
549      * @param aLocale
550      *            The locale.
551      * @return the resource bundle for this report.
552      */
553     private static ResourceBundle getBundle(final Locale aLocale) {
554         return ResourceBundle.getBundle("qalab-report", aLocale, MergeAndChartReport.class.getClassLoader());
555     }
556 
557     public void setXAxisSummaryTitle(String xAxisSummaryTitle) {
558     	this.xAxisSummaryTitle = xAxisSummaryTitle;
559     }
560 
561     public void setXAxisTitle(String xAxisTitle) {
562     	this.xAxisTitle = xAxisTitle;
563     }
564 
565     public void setYAxisSummaryTitle(String yAxisSummaryTitle) {
566     	this.yAxisSummaryTitle = yAxisSummaryTitle;
567     }
568 
569     public void setYAxisTitle(String yAxisTitle) {
570     	this.yAxisTitle = yAxisTitle;
571     }
572 
573     /**
574      * Validates the parameters supplied by maven 2.
575      *
576      * @throws MavenReportException
577      *             if any supplied params are wrong.
578      */
579     private void validate() throws MavenReportException {
580         try {
581             Utils.checkFile(qalabFile, "qalabFile");
582             theXmlStream = new FileInputStream(qalabFile);
583         } catch (IOException ioex) {
584             throw new MavenReportException(ioex.getMessage(), ioex);
585         }
586 
587         if (styleSheet == null) {
588             try {
589                 theStyleSheetStream = Utils.extractAsInputStream(chartBundledXsl);
590             } catch (IOException ioex) {
591                 throw new MavenReportException("Could not find the default stylesheet. " + ioex.getMessage(), ioex);
592             }
593         } else {
594             try {
595                 Utils.checkFile(styleSheet, "styleSheet");
596                 theStyleSheetStream = new FileInputStream(styleSheet);
597             } catch (IOException ioex) {
598                 throw new MavenReportException(ioex.getMessage(), ioex);
599             }
600         }
601 
602         theOffset = Utils.formatDateBasedOnOffset(startTimeHoursOffset);
603     }
604 }
605 /*
606  *                   ObjectLab is sponsoring QALab
607  *
608  * Based in London, we are world leaders in the design and development
609  * of bespoke applications for the securities financing markets.
610  *
611  * <a href="http://www.objectlab.co.uk/open">Click here to learn more about us</a>
612  *           ___  _     _           _   _          _
613  *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
614  *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
615  *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
616  *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
617  *                   |__/
618  *
619  *                     www.ObjectLab.co.uk
620  */