View Javadoc

1   package org.codehaus.mojo.dashboard.report.plugin;
2   
3   /*
4    * Copyright 2006 David Vicente
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.io.File;
20  import java.io.FileInputStream;
21  import java.io.FileNotFoundException;
22  import java.io.FileOutputStream;
23  import java.io.IOException;
24  import java.io.InputStreamReader;
25  import java.io.OutputStreamWriter;
26  import java.io.UnsupportedEncodingException;
27  import java.text.NumberFormat;
28  import java.text.ParseException;
29  import java.util.Date;
30  import java.util.HashMap;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.Locale;
34  import java.util.Map;
35  import java.util.StringTokenizer;
36  import java.util.Vector;
37  
38  import javax.xml.parsers.DocumentBuilder;
39  import javax.xml.parsers.DocumentBuilderFactory;
40  import javax.xml.parsers.FactoryConfigurationError;
41  import javax.xml.parsers.ParserConfigurationException;
42  
43  import net.sourceforge.cobertura.coveragedata.CoverageData;
44  import net.sourceforge.cobertura.coveragedata.CoverageDataFileHandler;
45  import net.sourceforge.cobertura.coveragedata.ProjectData;
46  
47  import org.apache.maven.artifact.repository.ArtifactRepository;
48  import org.apache.maven.model.Plugin;
49  import org.apache.maven.model.ReportPlugin;
50  import org.apache.maven.plugin.logging.Log;
51  import org.apache.maven.plugins.surefire.report.SurefireReportParser;
52  import org.apache.maven.project.MavenProject;
53  import org.apache.maven.project.MavenProjectBuilder;
54  import org.apache.maven.project.ProjectBuildingException;
55  import org.apache.maven.reporting.MavenReportException;
56  import org.apache.xpath.XPathAPI;
57  import org.apache.xpath.objects.XObject;
58  import org.codehaus.mojo.dashboard.report.plugin.beans.AbstractReportBean;
59  import org.codehaus.mojo.dashboard.report.plugin.beans.CheckstyleError;
60  import org.codehaus.mojo.dashboard.report.plugin.beans.CheckstyleReportBean;
61  import org.codehaus.mojo.dashboard.report.plugin.beans.CloverReportBean;
62  import org.codehaus.mojo.dashboard.report.plugin.beans.CoberturaReportBean;
63  import org.codehaus.mojo.dashboard.report.plugin.beans.CpdReportBean;
64  import org.codehaus.mojo.dashboard.report.plugin.beans.DashBoardMavenProject;
65  import org.codehaus.mojo.dashboard.report.plugin.beans.FindBugsReportBean;
66  import org.codehaus.mojo.dashboard.report.plugin.beans.JDependReportBean;
67  import org.codehaus.mojo.dashboard.report.plugin.beans.PmdReportBean;
68  import org.codehaus.mojo.dashboard.report.plugin.beans.SurefireReportBean;
69  import org.codehaus.mojo.dashboard.report.plugin.beans.TagListReportBean;
70  import org.codehaus.mojo.dashboard.report.plugin.beans.XRefPackageBean;
71  import org.codehaus.mojo.jdepend.JDependXMLReportParser;
72  import org.codehaus.mojo.jdepend.objects.JDPackage;
73  import org.codehaus.plexus.util.FileUtils;
74  import org.codehaus.plexus.util.StringInputStream;
75  import org.codehaus.plexus.util.StringUtils;
76  import org.codehaus.plexus.util.interpolation.MapBasedValueSource;
77  import org.codehaus.plexus.util.interpolation.ObjectBasedValueSource;
78  import org.codehaus.plexus.util.interpolation.RegexBasedInterpolator;
79  import org.codehaus.plexus.util.xml.Xpp3Dom;
80  import org.w3c.dom.Document;
81  import org.w3c.dom.Element;
82  import org.w3c.dom.NodeList;
83  import org.xml.sax.InputSource;
84  import org.xml.sax.SAXException;
85  
86  import com.thoughtworks.xstream.XStream;
87  import com.thoughtworks.xstream.io.xml.DomDriver;
88  
89  /**
90   * <ul>
91   * <li>Add "CheckStyle Violations" graph written by <a href="mailto:srivollet@objectif-informatique.fr">Sylvain
92   * Rivollet</a></li>
93   * <li>Add Clover support written by <a href="mailto:mbeerman@yahoo.com">Matthew Beermann</a></li>
94   * </ul>
95   * 
96   * @author <a href="dvicente72@gmail.com">David Vicente</a>
97   */
98  public class DashBoardUtils
99  {
100     /**
101      * 
102      */
103     private Log log;
104 
105     /**
106      * 
107      */
108     private static DashBoardUtils dashBoardUtils = null;
109 
110     /**
111      * <p>
112      * The Clover datafile location.
113      * </p>
114      * expression="${project.build.directory}/site/clover/clover.xml"
115      */
116     private final String cloverDataFile = "site/clover/clover.xml";
117 
118     /**
119      * <p>
120      * The Cobertura Datafile Location.
121      * </p>
122      * expression="${basedir}/cobertura.ser"
123      */
124     private final String coberturaDataFile = "cobertura.ser";
125 
126     /**
127      * <p>
128      * The PMD Datafile Location.
129      * </p>
130      * expression="${project.build.directory}/pmd.xml"
131      */
132     private final String pmdDataFile = "pmd.xml";
133 
134     /**
135      * <p>
136      * The CPD Datafile Location.
137      * </p>
138      * expression="${project.build.directory}/cpd.xml"
139      */
140     private final String cpdDataFile = "cpd.xml";
141 
142     /**
143      * <p>
144      * The checkstyle Datafile Location.
145      * </p>
146      * expression="${project.build.directory}/checkstyle-result.xml"
147      */
148     private final String checkstyleDataFile = "checkstyle-result.xml";
149 
150     /**
151      * <p>
152      * The JDepend Datafile Location.
153      * </p>
154      * expression="${project.build.directory}/jdepend-report.xml"
155      */
156     private final String jDependDataFile = "jdepend-report.xml";
157 
158     /**
159      * <p>
160      * The FindBugs Datafile Location.
161      * </p>
162      * expression="${project.build.directory}/findbugs.xml"
163      */
164     private final String findBugsDataFile = "findbugs.xml";
165 
166     /**
167      * <p>
168      * The Taglist Datafile Location.
169      * </p>
170      * expression="${project.build.directory}/taglist/taglist.xml"
171      */
172     private static String taglistDataFile = "taglist/taglist.xml";
173 
174     /**
175      * The local repository.
176      */
177     private ArtifactRepository localRepo;
178 
179     /**
180      * Project builder
181      */
182     private MavenProjectBuilder projectBuilder;
183 
184     /**
185      * 
186      */
187     private final HashMap projectMap = new HashMap();
188 
189     private boolean dbPersist = false;
190 
191     /**
192      * @param log
193      * @param mavenProjectBuilder
194      * @param localRepository
195      * @return
196      */
197     public static DashBoardUtils getInstance( Log log, MavenProjectBuilder mavenProjectBuilder,
198                                               ArtifactRepository localRepository, boolean dbPersist )
199     {
200 
201         if ( dashBoardUtils == null )
202         {
203             dashBoardUtils = new DashBoardUtils( log, mavenProjectBuilder, localRepository, dbPersist );
204         }
205         else
206         {
207             dashBoardUtils.log = log;
208             dashBoardUtils.projectBuilder = mavenProjectBuilder;
209             dashBoardUtils.localRepo = localRepository;
210             dashBoardUtils.dbPersist = dbPersist;
211         }
212         return dashBoardUtils;
213     }
214 
215     /**
216      * private Constructor
217      */
218     private DashBoardUtils( Log log, MavenProjectBuilder mavenProjectBuilder, ArtifactRepository localRepository,
219                             boolean dbPersist )
220     {
221         this.log = log;
222         this.projectBuilder = mavenProjectBuilder;
223         this.localRepo = localRepository;
224         this.dbPersist = dbPersist;
225     }
226 
227     public DashBoardMavenProject getDashBoardMavenProject( MavenProject project, String dashboardDataFile,
228                                                            Date generatedDate )
229     {
230 
231         String projectName = project.getName();
232         // Fixes MOJO-801. NPE in a particular three level multimodule build
233         this.fillProjectMap( project );
234 
235         DashBoardMavenProject mavenProject;
236         if ( project.getModules().size() > 0 )
237         {
238             // String artefactId = project.getGroupId() + "." + project.getArtifactId();
239             mavenProject =
240                 new DashBoardMavenProject( project.getArtifactId(), project.getGroupId(), projectName,
241                                            project.getVersion() );
242             for ( int i = 0; i < project.getModules().size(); i++ )
243             {
244                 String modulename = (String) project.getModules().get( i );
245 
246                 MavenProject proj = this.getModuleMavenProject( project, modulename );
247                 String key = proj.getGroupId() + "." + proj.getArtifactId();
248                 if ( this.projectMap.containsKey( key ) )
249                 {
250                     MavenProject realproj = (MavenProject) this.projectMap.get( key );
251                     DashBoardMavenProject subMavenProject =
252                         dashBoardUtils.getDashBoardMavenProject( realproj, dashboardDataFile, generatedDate );
253                     mavenProject.addModule( subMavenProject );
254                 }
255 
256             }
257 
258         }
259         else
260         {
261             mavenProject =
262                 new DashBoardMavenProject( project.getArtifactId(), project.getGroupId(), projectName,
263                                            project.getVersion() );
264             for ( Iterator reports = project.getReportPlugins().iterator(); reports.hasNext(); )
265             {
266                 ReportPlugin report = (ReportPlugin) reports.next();
267                 String artifactId = report.getArtifactId();
268                 AbstractReportBean dashBoardReport = null;
269                 if ( "maven-checkstyle-plugin".equals( artifactId ) || "checkstyle-maven-plugin".equals( artifactId ) )
270                 {
271                     dashBoardReport = this.getCheckstyleReport( project, generatedDate );
272                 }
273                 else if ( "maven-clover-plugin".equals( artifactId ) )
274                 {
275                     dashBoardReport = this.getCloverReport( project, generatedDate );
276                 }
277                 else if ( "maven-surefire-report-plugin".equals( artifactId )
278                                 || "surefire-report-maven-plugin".equals( artifactId ) )
279                 {
280                     dashBoardReport = this.getSurefireReport( project, generatedDate );
281                 }
282                 else if ( "cobertura-maven-plugin".equals( artifactId ) || "maven-cobertura-plugin".equals( artifactId ) )
283                 {
284                     dashBoardReport = this.getCoberturaReport( project, generatedDate );
285                 }
286                 else if ( "maven-pmd-plugin".equals( artifactId ) || "pmd-maven-plugin".equals( artifactId ) )
287                 {
288                     dashBoardReport = this.getCpdReport( project, generatedDate );
289                     if ( dashBoardReport != null )
290                     {
291                         mavenProject.addReport( dashBoardReport );
292                     }
293                     dashBoardReport = this.getPmdReport( project, generatedDate );
294                 }
295                 else if ( "maven-findbugs-plugin".equals( artifactId ) || "findbugs-maven-plugin".equals( artifactId ) )
296                 {
297                     dashBoardReport = this.getFindBugsReport( project, generatedDate );
298                 }
299                 else if ( "maven-jdepend-plugin".equals( artifactId ) || "jdepend-maven-plugin".equals( artifactId ) )
300                 {
301                     if ( !this.dbPersist )
302                     {
303                         dashBoardReport = this.getJDependReport( project, generatedDate );
304                     }
305                 }
306                 else if ( "maven-taglist-plugin".equals( artifactId ) || "taglist-maven-plugin".equals( artifactId ) )
307                 {
308                     dashBoardReport = this.getTaglistReport( project, generatedDate );
309                 }
310                 if ( dashBoardReport != null )
311                 {
312                     mavenProject.addReport( dashBoardReport );
313                 }
314             }
315         }
316         return mavenProject;
317     }
318 
319     /**
320      * Fixes MOJO-801. NPE in a particular three level multimodule build
321      * 
322      * @param project
323      */
324     private void fillProjectMap( MavenProject project )
325     {
326         if ( project.getModules().size() > 0 )
327         {
328             Iterator iter = project.getCollectedProjects().iterator();
329 
330             while ( iter.hasNext() )
331             {
332                 MavenProject proj = (MavenProject) iter.next();
333                 String key = proj.getGroupId() + "." + proj.getArtifactId();
334                 if ( !this.projectMap.containsKey( key ) )
335                 {
336                     this.projectMap.put( key, proj );
337                 }
338             }
339         }
340         else
341         {
342             String key = project.getGroupId() + "." + project.getArtifactId();
343             if ( !this.projectMap.containsKey( key ) )
344             {
345                 this.projectMap.put( key, project );
346             }
347         }
348     }
349 
350     /**
351      * @param project
352      * @param module
353      * @return
354      */
355     private MavenProject getModuleMavenProject( MavenProject project, String module )
356     {
357         MavenProject projectModule = null;
358         File f = new File( project.getBasedir(), module + "/pom.xml" );
359         if ( f.exists() )
360         {
361             try
362             {
363                 projectModule = this.projectBuilder.build( f, this.localRepo, null );
364             }
365             catch ( ProjectBuildingException e )
366             {
367                 this.log.error( "Unable to read local module-POM \"" + module + "\".", e );
368             }
369         }
370         return projectModule;
371     }
372 
373     /**
374      * get the CoberturaReportBean which represents the Cobertura .ser file analysis
375      * 
376      * @param projectName
377      * @param coberturaDataFile
378      * @return
379      */
380     protected CoberturaReportBean getCoberturaReport( MavenProject project, Date generatedDate )
381     {
382 
383         CoberturaReportBean coberturaReport = new CoberturaReportBean( generatedDate );
384 
385         File coberturaFile = this.getCoberturaDataFile( project );
386 
387         if ( coberturaFile != null && coberturaFile.exists() && coberturaFile.isFile() )
388         {
389             this.log.debug( "getCoberturaReport = " + coberturaFile.toString() );
390             ProjectData projectData = CoverageDataFileHandler.loadCoverageData( coberturaFile );
391             if ( projectData != null )
392             {
393                 coberturaReport.setNbClasses( projectData.getNumberOfClasses() );
394                 double lineCoverage = -1;
395                 double branchCoverage = -1;
396 
397                 if ( projectData.getNumberOfValidLines() > 0 )
398                 {
399                     lineCoverage = projectData.getLineCoverageRate();
400                 }
401                 if ( projectData.getNumberOfValidBranches() > 0 )
402                 {
403                     branchCoverage = projectData.getBranchCoverageRate();
404                 }
405                 coberturaReport.setLineCoverRate( lineCoverage );
406                 coberturaReport.setBranchCoverRate( branchCoverage );
407                 coberturaReport.setNumberOfCoveredBranches( projectData.getNumberOfCoveredBranches() );
408                 coberturaReport.setNumberOfValidBranches( projectData.getNumberOfValidBranches() );
409                 coberturaReport.setNumberOfCoveredLines( projectData.getNumberOfCoveredLines() );
410                 coberturaReport.setNumberOfValidLines( projectData.getNumberOfValidLines() );
411                 // System.out.println( "DashBoardReportGenerator this.use_cobertura_report = true" );
412             }
413             else
414             {
415                 coberturaReport = null;
416             }
417         }
418         else
419         {
420             coberturaReport = null;
421         }
422         return coberturaReport;
423     }
424 
425     /**
426      * @param projectName
427      * @param checkstyleDataFile
428      * @return
429      */
430     protected CheckstyleReportBean getCheckstyleReport( MavenProject project, Date generatedDate )
431     {
432         CheckstyleReportBean checkstyleReport = new CheckstyleReportBean( generatedDate );
433         File checkstyleFile = new File( project.getBuild().getDirectory(), this.checkstyleDataFile );
434         if ( checkstyleFile.exists() && checkstyleFile.isFile() )
435         {
436             Document doc = this.getDocument( checkstyleFile );
437             if ( doc != null )
438             {
439                 Element cpd = doc.getDocumentElement();
440                 NodeList files = cpd.getElementsByTagName( "file" );
441                 NodeList total = cpd.getElementsByTagName( "error" );
442                 int nbInfos = 0;
443                 int nbWarnings = 0;
444                 int nbErrors = 0;
445                 for ( int i = 0; i < total.getLength(); i++ )
446                 {
447                     Element error = (Element) total.item( i );
448                     CheckstyleError checkstyleError = new CheckstyleError();
449                     String severity = error.getAttribute( "severity" );
450                     if ( severity.equalsIgnoreCase( "info" ) )
451                     {
452                         nbInfos++;
453                     }
454                     else if ( severity.equalsIgnoreCase( "warning" ) )
455                     {
456                         nbWarnings++;
457                     }
458                     else if ( severity.equalsIgnoreCase( "error" ) )
459                     {
460                         nbErrors++;
461                     }
462                     // error management for Checkstyle Violations Chart. Fixes MOJO-679 .
463                     // Written by <a href="mailto:srivollet@objectif-informatique.fr">Sylvain Rivollet</a>.
464                     checkstyleError.setType( error.getAttribute( "severity" ) );
465                     checkstyleError.setNameClass( error.getAttribute( "source" ) );
466                     checkstyleError.setMessage( error.getAttribute( "message" ) );
467                     checkstyleReport.addError( checkstyleError );
468                 }
469                 checkstyleReport.setNbClasses( files.getLength() );
470                 checkstyleReport.setNbErrors( nbErrors );
471                 checkstyleReport.setNbInfos( nbInfos );
472                 checkstyleReport.setNbTotal( total.getLength() );
473                 checkstyleReport.setNbWarnings( nbWarnings );
474             }
475             else
476             {
477                 checkstyleReport = null;
478             }
479         }
480         else
481         {
482             checkstyleReport = null;
483         }
484 
485         return checkstyleReport;
486 
487     }
488 
489     /**
490      * @param project
491      * @return
492      */
493     protected CpdReportBean getCpdReport( MavenProject project, Date generatedDate )
494     {
495         CpdReportBean cpdReport = new CpdReportBean( generatedDate );
496         File cpdFile = new File( project.getBuild().getDirectory(), this.cpdDataFile );
497         if ( cpdFile.exists() && cpdFile.isFile() )
498         {
499             Document doc = this.getDocument( cpdFile );
500             if ( doc != null )
501             {
502                 Element cpd = doc.getDocumentElement();
503                 NodeList duplications = cpd.getElementsByTagName( "duplication" );
504                 NodeList files = cpd.getElementsByTagName( "file" );
505                 Vector filelist = new Vector();
506                 for ( int i = 0; i < files.getLength(); i++ )
507                 {
508                     Element file = (Element) files.item( i );
509                     if ( !filelist.contains( file.getAttribute( "path" ) ) )
510                     {
511                         filelist.add( file.getAttribute( "path" ) );
512                     }
513                 }
514                 cpdReport.setNbClasses( filelist.size() );
515                 cpdReport.setNbDuplicate( duplications.getLength() );
516             }
517             else
518             {
519                 cpdReport = null;
520             }
521         }
522         else
523         {
524             cpdReport = null;
525         }
526         return cpdReport;
527     }
528 
529     /**
530      * @param project
531      * @return
532      */
533     protected PmdReportBean getPmdReport( MavenProject project, Date generatedDate )
534     {
535         PmdReportBean pmdReport = new PmdReportBean( generatedDate );
536         File pmdFile = new File( project.getBuild().getDirectory(), this.pmdDataFile );
537         if ( pmdFile.exists() && pmdFile.isFile() )
538         {
539             Document doc = this.getDocument( pmdFile );
540             if ( doc != null )
541             {
542                 Element pmd = doc.getDocumentElement();
543                 NodeList files = pmd.getElementsByTagName( "file" );
544                 NodeList violations = pmd.getElementsByTagName( "violation" );
545                 pmdReport.setNbClasses( files.getLength() );
546                 pmdReport.setNbViolations( violations.getLength() );
547             }
548             else
549             {
550                 pmdReport = null;
551             }
552         }
553         else
554         {
555             pmdReport = null;
556         }
557         return pmdReport;
558 
559     }
560 
561     /**
562      * @param project
563      * @return
564      */
565     protected SurefireReportBean getSurefireReport( MavenProject project, Date generatedDate )
566     {
567         SurefireReportBean surefireReport = new SurefireReportBean( generatedDate );
568 
569         File surefireDirectory = this.getSurefireDirectory( project );
570 
571         if ( surefireDirectory != null && surefireDirectory.exists() && surefireDirectory.isDirectory() )
572         {
573             // SurefireReportParser report = new SurefireReportParser( surefireDirectory, Locale.getDefault() );
574             File[] surefireDirectories = { surefireDirectory };
575             SurefireReportParser report = new SurefireReportParser( surefireDirectories, Locale.getDefault() );
576             List testSuites;
577             try
578             {
579                 testSuites = report.parseXMLReportFiles();
580                 Map summary = report.getSummary( testSuites );
581 
582                 surefireReport.setNbTests( Integer.parseInt( (String) summary.get( "totalTests" ) ) );
583 
584                 surefireReport.setNbErrors( Integer.parseInt( (String) summary.get( "totalErrors" ) ) );
585 
586                 surefireReport.setNbFailures( Integer.parseInt( (String) summary.get( "totalFailures" ) ) );
587 
588                 if ( summary.get( "totalSkipped" ) != null )
589                 {
590                     surefireReport.setNbSkipped( Integer.parseInt( (String) summary.get( "totalSkipped" ) ) );
591                 }
592                 else
593                 {
594                     surefireReport.setNbSkipped( 0 );
595                 }
596                 // MOJO-624 correction
597                 NumberFormat format = NumberFormat.getInstance( Locale.getDefault() );
598                 String percent = (String) summary.get( "totalPercentage" );
599                 try
600                 {
601                     surefireReport.setSucessRate( format.parse( percent ).doubleValue() );
602                 }
603                 catch ( ParseException e )
604                 {
605                     this.log.info( "SurefireReportBean setSucessRate Unexpected number format exception..", e );
606                     surefireReport.setSucessRate( 0.0 );
607                 }
608                 String elapsed = (String) summary.get( "totalElapsedTime" );
609                 try
610                 {
611                     surefireReport.setElapsedTime( format.parse( elapsed ).doubleValue() );
612                 }
613                 catch ( ParseException e )
614                 {
615                     this.log.info( "SurefireReportBean setElapsedTime Unexpected number format exception..", e );
616                     surefireReport.setElapsedTime( 0.0 );
617                 }
618 
619             }
620             catch ( MavenReportException e )
621             {
622                 this.log.error( "SurefireReportBean creation failed.", e );
623                 surefireReport = null;
624             }
625         }
626         else
627         {
628             surefireReport = null;
629         }
630         return surefireReport;
631 
632     }
633 
634     /**
635      * Fixes MOJO-813. addition of Clover support written by <a href="mailto:mbeerman@yahoo.com">Matthew Beermann</a>
636      * 
637      * @param project
638      * @return
639      */
640     protected CloverReportBean getCloverReport( MavenProject project, Date generatedDate )
641     {
642         CloverReportBean cloverReport = new CloverReportBean( generatedDate );
643 
644         File cloverReportFile = new File( project.getBuild().getDirectory(), this.cloverDataFile );
645 
646         if ( cloverReportFile != null && cloverReportFile.exists() && cloverReportFile.isFile() )
647         {
648             try
649             {
650                 Document doc = this.getDocument( cloverReportFile );
651                 if ( doc != null )
652                 {
653 
654                     NodeList allMetrics = doc.getElementsByTagName( "metrics" );
655                     Element metrics = null;
656                     for ( int i = 0; i < allMetrics.getLength(); i++ )
657                     {
658                         Element candidate = (Element) allMetrics.item( i );
659                         if ( candidate.getParentNode().getNodeName().equals( "project" ) )
660                         {
661                             metrics = candidate;
662                             break;
663                         }
664                     }
665                     if ( metrics == null )
666                     {
667                         return null;
668                     }
669 
670                     cloverReport.setConditionals( Integer.parseInt( metrics.getAttribute( "conditionals" ) ) );
671                     cloverReport.setStatements( Integer.parseInt( metrics.getAttribute( "statements" ) ) );
672                     cloverReport.setMethods( Integer.parseInt( metrics.getAttribute( "methods" ) ) );
673                     cloverReport.setElements( Integer.parseInt( metrics.getAttribute( "elements" ) ) );
674 
675                     cloverReport.setCoveredConditionals( Integer.parseInt( metrics.getAttribute( "coveredconditionals" ) ) );
676                     cloverReport.setCoveredStatements( Integer.parseInt( metrics.getAttribute( "coveredstatements" ) ) );
677                     cloverReport.setCoveredMethods( Integer.parseInt( metrics.getAttribute( "coveredmethods" ) ) );
678                     cloverReport.setCoveredElements( Integer.parseInt( metrics.getAttribute( "coveredelements" ) ) );
679                 }
680                 else
681                 {
682                     cloverReport = null;
683                 }
684 
685             }
686             catch ( Exception e )
687             {
688                 this.log.error( "CloverReportBean creation failed.", e );
689                 cloverReport = null;
690             }
691         }
692         else
693         {
694             cloverReport = null;
695         }
696 
697         return cloverReport;
698     }
699 
700     /**
701      * get the JDependReportBean which represents the Cobertura .ser file analysis
702      * 
703      * @param project
704      * @return
705      */
706     protected JDependReportBean getJDependReport( MavenProject project, Date generatedDate )
707     {
708 
709         this.log.debug( "JDependReportBean creation = " + project.getName() + "." );
710         JDependReportBean jDependReport = new JDependReportBean( generatedDate );
711 
712         File coberturaFile = new File( project.getBasedir(), this.coberturaDataFile );
713         File jDependFile = new File( project.getBuild().getDirectory(), this.jDependDataFile );
714         ProjectData projectData = null;
715         if ( coberturaFile.exists() && coberturaFile.isFile() )
716         {
717             projectData = CoverageDataFileHandler.loadCoverageData( coberturaFile );
718         }
719         if ( jDependFile.exists() && jDependFile.isFile() )
720         {
721             JDependXMLReportParser xmlParser;
722             try
723             {
724                 xmlParser = new JDependXMLReportParser( jDependFile );
725                 List packages = xmlParser.getPackages();
726                 if ( packages != null && packages.size() > 0 )
727                 {
728 
729                     Iterator iter = packages.iterator();
730                     while ( iter.hasNext() )
731                     {
732                         JDPackage pack = (JDPackage) iter.next();
733                         XRefPackageBean bean = new XRefPackageBean();
734                         bean.setPackageName( pack.getPackageName() );
735                         int iCa = Integer.parseInt( pack.getStats().getCa() );
736                         bean.setAfferentCoupling( new Integer( iCa ) );
737                         if ( projectData != null )
738                         {
739                             CoverageData data = projectData.getChild( pack.getPackageName() );
740                             if ( data != null )
741                             {
742                                 bean.setLineCoverRate( data.getLineCoverageRate() );
743                                 bean.setBranchCoverRate( data.getBranchCoverageRate() );
744                             }
745                         }
746                         jDependReport.addPackage( bean );
747                     }
748                 }
749                 else
750                 {
751                     jDependReport = null;
752                 }
753             }
754             catch ( ParserConfigurationException e )
755             {
756                 this.log.error( "JDependReportBean creation failed.", e );
757                 jDependReport = null;
758             }
759             catch ( SAXException e )
760             {
761                 this.log.error( "JDependReportBean creation failed.", e );
762                 jDependReport = null;
763             }
764             catch ( IOException e )
765             {
766                 this.log.error( "JDependReportBean creation failed.", e );
767                 jDependReport = null;
768             }
769         }
770         else
771         {
772             jDependReport = null;
773         }
774 
775         return jDependReport;
776 
777     }
778 
779     /**
780      * @param projectName
781      * @param FindBugsDataFile
782      * @return
783      */
784     protected FindBugsReportBean getFindBugsReport( MavenProject project, Date generatedDate )
785     {
786         FindBugsReportBean findBugsReport = new FindBugsReportBean( generatedDate );
787         File findBugsFile = new File( project.getBuild().getDirectory(), this.findBugsDataFile );
788         if ( findBugsFile.exists() && findBugsFile.isFile() )
789         {
790             Document doc = this.getDocument( findBugsFile );
791             if ( doc != null )
792             {
793                 Element root = doc.getDocumentElement();
794                 NodeList files = root.getElementsByTagName( "file" );
795                 NodeList bugs = root.getElementsByTagName( "BugInstance" );
796                 NodeList missing = root.getElementsByTagName( "MissingClass" );
797                 findBugsReport.setNbClasses( files.getLength() );
798                 findBugsReport.setNbErrors( 0 );
799                 findBugsReport.setNbBugs( bugs.getLength() );
800                 findBugsReport.setNbMissingClasses( missing.getLength() );
801                 for ( int i = 0; i < bugs.getLength(); i++ )
802                 {
803                     Element bugInstance = (Element) bugs.item( i );
804                     String category = bugInstance.getAttribute( "category" );
805                     findBugsReport.addCategory( category );
806                     String priority = bugInstance.getAttribute( "priority" );
807                     findBugsReport.addPriority( priority );
808                 }
809             }
810             else
811             {
812                 findBugsReport = null;
813             }
814         }
815         else
816         {
817             findBugsReport = null;
818         }
819 
820         return findBugsReport;
821     }
822 
823     /**
824      * @param project
825      * @param generatedDate
826      * @return
827      */
828     protected TagListReportBean getTaglistReport( MavenProject project, Date generatedDate )
829     {
830         TagListReportBean taglistReport = new TagListReportBean( generatedDate );
831         File taglistFile = new File( project.getBuild().getDirectory(), taglistDataFile );
832         if ( taglistFile.exists() && taglistFile.isFile() )
833         {
834             Document doc = this.getDocument( taglistFile );
835             if ( doc != null )
836             {
837                 Element root = doc.getDocumentElement();
838                 NodeList tags = root.getElementsByTagName( "tag" );
839                 for ( int i = 0; i < tags.getLength(); i++ )
840                 {
841                     Element tag = (Element) tags.item( i );
842                     String tagName = tag.getAttribute( "name" );
843                     Integer tagCount = Integer.valueOf( tag.getAttribute( "count" ) );
844                     taglistReport.setTag( tagName, tagCount );
845                 }
846                 NodeList files = root.getElementsByTagName( "file" );
847                 Map classFiles = new HashMap();
848                 for ( int i = 0; i < files.getLength(); i++ )
849                 {
850                     Element file = (Element) files.item( i );
851                     String className = file.getAttribute( "name" );
852                     classFiles.put( className, new Integer( 1 ) );
853                 }
854                 taglistReport.setNbClasses( classFiles.size() );
855             }
856             else
857             {
858                 taglistReport = null;
859             }
860         }
861         else
862         {
863             taglistReport = null;
864         }
865 
866         return taglistReport;
867     }
868 
869     /**
870      * @param xmlFilename
871      * @return
872      */
873     private Document getDocument( File xmlFilename )
874     {
875         Document doc = null;
876 
877         FileInputStream fileInputStream;
878         try
879         {
880             fileInputStream = new FileInputStream( xmlFilename );
881             InputStreamReader inputStreamReader = new InputStreamReader( fileInputStream, "UTF-8" );
882             InputSource inputSource = new InputSource( inputStreamReader );
883 
884             DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
885             // this.log.info(builder.getClass().toString());
886             doc = builder.parse( inputSource );
887         }
888         catch ( FileNotFoundException e )
889         {
890             this.log.error( "DashBoardUtils getDocument() FileNotFoundException : ", e );
891             doc = null;
892         }
893         catch ( UnsupportedEncodingException e )
894         {
895             this.log.error( "DashBoardUtils getDocument() UnsupportedEncodingException : ", e );
896             doc = null;
897         }
898         catch ( ParserConfigurationException e )
899         {
900             this.log.error( "DashBoardUtils getDocument() ParserConfigurationException : ", e );
901             doc = null;
902         }
903         catch ( FactoryConfigurationError e )
904         {
905             this.log.error( "DashBoardUtils getDocument() FactoryConfigurationError : ", e );
906             doc = null;
907         }
908         catch ( SAXException e )
909         {
910             this.log.error( "DashBoardUtils getDocument() SAXException : ", e );
911             doc = null;
912         }
913         catch ( IOException e )
914         {
915             this.log.error( "DashBoardUtils getDocument() IOException : ", e );
916             doc = null;
917         }
918 
919         return doc;
920     }
921 
922     /**
923      * @param project
924      * @param dashboardDataFile
925      * @return
926      */
927     protected DashBoardMavenProject readXMLDashBoardReport( MavenProject project, String dashboardDataFile )
928     {
929         DashBoardMavenProject mavenProject = null;
930         try
931         {
932 
933             // Instanciation de la classe XStream
934             XStream xstream = new XStream( new DomDriver() );
935             // Instanciation d'un fichier
936             File fichier = new File( project.getBuild().getDirectory(), dashboardDataFile );
937 
938             // Redirection du fichier /target/dashboard-report.xml vers un flux
939             // d'entr�e fichier
940             FileInputStream fis = new FileInputStream( fichier );
941 
942             try
943             {
944                 xstream.setMode( XStream.NO_REFERENCES );
945                 // Convertion du contenu de l'objet DashBoardReportBean en XML
946                 xstream.alias( "MavenProject", DashBoardMavenProject.class );
947                 xstream.alias( "xrefpackage", XRefPackageBean.class );
948                 xstream.alias( "checkstyleerror", CheckstyleError.class );
949                 xstream.useAttributeFor( "id", Long.class );
950                 xstream.useAttributeFor( "artifactId", String.class );
951                 xstream.useAttributeFor( "groupId", String.class );
952                 xstream.useAttributeFor( "version", String.class );
953                 xstream.useAttributeFor( "projectName", String.class );
954                 xstream.useAttributeFor( "generatedDate", Date.class );
955                 xstream.useAttributeFor( "averageAfferentCoupling", String.class );
956                 xstream.useAttributeFor( "nbPackages", String.class );
957                 xstream.useAttributeFor( "sumAC", String.class );
958                 // D�s�rialisation du fichier /target/dashboard-multi-report.xml vers un nouvel
959                 // objet DashBoardReportBean
960                 mavenProject = (DashBoardMavenProject) xstream.fromXML( fis );
961 
962             }
963             finally
964             {
965                 // On s'assure de fermer le flux quoi qu'il arrive
966                 fis.close();
967             }
968         }
969         catch ( FileNotFoundException e )
970         {
971             System.out.println( "readXMLDashBoardReport() for project " + project.getName() + " failed :"
972                             + e.getMessage() );
973             mavenProject = null;
974         }
975         catch ( IOException ioe )
976         {
977             System.out.println( "readXMLDashBoardReport() for project " + project.getName() + " failed :"
978                             + ioe.getMessage() );
979             mavenProject = null;
980         }
981         return mavenProject;
982     }
983 
984     /**
985      * @param project
986      * @param dashBoardReport
987      * @param dashboardDataFile
988      */
989     protected void saveXMLDashBoardReport( MavenProject project, DashBoardMavenProject mavenProject,
990                                            String dashboardDataFile )
991     {
992         try
993         {
994             // Instanciation de la classe XStream
995             XStream xstream = new XStream( new DomDriver() );
996             // Instanciation d'un fichier
997             File dir = new File( project.getBuild().getDirectory() );
998             if ( !dir.exists() )
999             {
1000                 dir.mkdirs();
1001             }
1002             File fichier = new File( dir, dashboardDataFile );
1003             // Instanciation d'un flux de sortie fichier vers le xml
1004             FileOutputStream fos = new FileOutputStream( fichier );
1005             OutputStreamWriter output = new OutputStreamWriter( fos, "UTF-8" );
1006             try
1007             {
1008                 output.write( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" );
1009                 xstream.setMode( XStream.NO_REFERENCES );
1010                 // Convertion du contenu de l'objet DashBoardReportBean en XML
1011                 xstream.alias( "MavenProject", DashBoardMavenProject.class );
1012                 xstream.alias( "xrefpackage", XRefPackageBean.class );
1013                 xstream.alias( "checkstyleerror", CheckstyleError.class );
1014                 xstream.useAttributeFor( "id", Long.class );
1015                 xstream.useAttributeFor( "artifactId", String.class );
1016                 xstream.useAttributeFor( "groupId", String.class );
1017                 xstream.useAttributeFor( "version", String.class );
1018                 xstream.useAttributeFor( "projectName", String.class );
1019                 xstream.useAttributeFor( "generatedDate", Date.class );
1020                 xstream.useAttributeFor( "averageAfferentCoupling", String.class );
1021                 xstream.useAttributeFor( "nbPackages", String.class );
1022                 xstream.useAttributeFor( "sumAC", String.class );
1023                 // S�rialisation de l'objet dashBoardReport dans /target/dashboard-report.xml
1024                 xstream.toXML( mavenProject, output );
1025             }
1026             finally
1027             {
1028                 // On s'assure de fermer le flux quoi qu'il arrive
1029                 fos.close();
1030             }
1031 
1032         }
1033         catch ( FileNotFoundException e )
1034         {
1035             this.log.error( "saveXMLDashBoardReport() failed.", e );
1036         }
1037         catch ( IOException ioe )
1038         {
1039             this.log.error( "saveXMLDashBoardReport() failed.", ioe );
1040         }
1041     }
1042 
1043     /**
1044      * get the Cobertura datafile. MOJO-644 : pb with different versions of Cobertura plugin. for cobertura 2.1
1045      * default-value="${project.build.directory}/cobertura/cobertura.ser" for cobertura 2.0
1046      * default-value="${basedir}/cobertura.ser" MOJO-674 : NumberFormatException fixed by using DefaultArtifactVersion
1047      * class MOJO-749 : NPE if dashboard called on parent project (when no cobertura version in pom.xml)
1048      * 
1049      * @param project
1050      *            MavenProject to be processed
1051      * @return cobertura.ser File object
1052      */
1053     private File getCoberturaDataFile( MavenProject project )
1054     {
1055         /*
1056          * HACK to address the broken datafile location code in Cobertura See
1057          * https://sourceforge.net/tracker/index.php?func=detail&aid=1543280&group_id=130558&atid=720017 Until patch is
1058          * commited, this hack will be in place.
1059          */
1060         File coberturaFile = null;
1061         File brokenDatafile = new File( project.getBasedir(), this.coberturaDataFile );
1062         File dataFile = new File( project.getBuild().getDirectory(), "cobertura/" + this.coberturaDataFile );
1063         if ( brokenDatafile != null && brokenDatafile.exists() )
1064         {
1065             try
1066             {
1067                 FileUtils.copyFile( brokenDatafile, dataFile );
1068                 brokenDatafile.delete();
1069                 coberturaFile = dataFile;
1070             }
1071             catch ( IOException e )
1072             {
1073                 coberturaFile = null;
1074             }
1075         }
1076 
1077         if ( dataFile != null && dataFile.exists() )
1078         {
1079             coberturaFile = dataFile;
1080         }
1081         else
1082         {
1083             coberturaFile = null;
1084         }
1085         return coberturaFile;
1086     }
1087 
1088     /**
1089      * get the Surefire directory as configured in surefire plugin configuration section. MOJO-615 : pb with different
1090      * surefire reports directories
1091      * 
1092      * @param project
1093      *            The Maven Project object
1094      * @return the surefire directory
1095      */
1096     private File getSurefireDirectory( MavenProject project )
1097     {
1098         File surefireDir = null;
1099         String dirPath =
1100             this.getConfiguration( project, "maven-surefire-plugin", "org.apache.maven.plugins", "reportsDirectory",
1101                                    "${project.build.directory}/surefire-reports" );
1102         if ( dirPath != null && dirPath.length() > 0 )
1103         {
1104             surefireDir = new File( dirPath );
1105         }
1106         return surefireDir;
1107     }
1108 
1109     /**
1110      * @param project
1111      * @param pluginArtifact
1112      * @param optionName
1113      * @param defaultValue
1114      * @return
1115      */
1116     private String getConfiguration( MavenProject project, String pluginArtifact, String pluginGroupId,
1117                                      String optionName, String defaultValue )
1118     {
1119         String result = null;
1120         String value = "";
1121         try
1122         {
1123             value = getMavenPluginConfiguration( project, pluginArtifact, pluginGroupId, optionName, "" );
1124             if ( value != null && value.length() > 0 )
1125             {
1126                 if ( value.indexOf( "$" ) > -1 )
1127                 {
1128                     result = this.getInterpolatorValue( project, value );
1129                 }
1130                 else
1131                 {
1132 
1133                     File dir = new File( value );
1134                     boolean isExists = dir.exists();
1135                     if ( !isExists )
1136                     {
1137                         File resultFile = FileUtils.resolveFile( project.getBasedir(), value );
1138                         result = resultFile.getAbsolutePath();
1139                     }
1140                     else
1141                     {
1142                         result = value;
1143                     }
1144                 }
1145             }
1146             else
1147             {
1148                 result = this.getInterpolatorValue( project, defaultValue );
1149             }
1150         }
1151         catch ( IOException e )
1152         {
1153             result = null;
1154             this.log.error( "DashBoardUtils getConfiguration() : ", e );
1155         }
1156         return result;
1157     }
1158 
1159     /**
1160      * @param project
1161      * @param value
1162      * @return
1163      */
1164     private String getInterpolatorValue( MavenProject project, String value )
1165     {
1166 
1167         RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
1168         interpolator.addValueSource( new ObjectBasedValueSource( project ) );
1169         interpolator.addValueSource( new MapBasedValueSource( project.getProperties() ) );
1170 
1171         String result = interpolator.interpolate( value, "project" );
1172 
1173         return result;
1174     }
1175 
1176     /**
1177      * Return the optionName value defined in a project for a given artifactId plugin.
1178      * 
1179      * @param project
1180      *            not null
1181      * @param pluginArtifact
1182      *            not null
1183      * @param optionName
1184      *            an Xpath expression from the plugin <code>&lt;configuration/&gt;</code>
1185      * @param defaultValue
1186      * @return the value for the option name (comma separated value in the case of list) or null if not found
1187      * @throws IOException
1188      *             if any
1189      */
1190     private static String getMavenPluginConfiguration( MavenProject project, String pluginArtifact,
1191                                                        String pluginGroupId, String optionName, String defaultValue )
1192         throws IOException
1193     {
1194         for ( Iterator it = project.getModel().getBuild().getPlugins().iterator(); it.hasNext(); )
1195         {
1196             Plugin plugin = (Plugin) it.next();
1197 
1198             if ( ( plugin.getGroupId().equals( pluginGroupId ) ) && ( plugin.getArtifactId().equals( pluginArtifact ) ) )
1199             {
1200                 Xpp3Dom pluginConf = (Xpp3Dom) plugin.getConfiguration();
1201 
1202                 if ( pluginConf != null )
1203                 {
1204                     StringBuffer sb = new StringBuffer();
1205                     try
1206                     {
1207                         Document doc =
1208                             DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
1209                                                                                              new StringInputStream(
1210                                                                                                                     pluginConf.toString() ) );
1211 
1212                         XObject obj = XPathAPI.eval( doc, "//configuration//" + optionName );
1213 
1214                         if ( StringUtils.isNotEmpty( obj.toString() ) )
1215                         {
1216                             StringTokenizer token = new StringTokenizer( obj.toString(), "\n " );
1217                             while ( token.hasMoreTokens() )
1218                             {
1219                                 sb.append( token.nextToken().trim() );
1220                                 if ( token.hasMoreElements() )
1221                                 {
1222                                     sb.append( "," );
1223                                 }
1224                             }
1225                             return sb.toString();
1226                         }
1227                     }
1228                     catch ( Exception e )
1229                     {
1230                         throw new IOException( "Exception occured" + e.getMessage() );
1231                     }
1232                 }
1233             }
1234         }
1235 
1236         return defaultValue;
1237     }
1238 }