1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  package org.codehaus.mojo.cobertura;
21  
22  import net.sourceforge.cobertura.coveragedata.CoverageDataFileHandler;
23  import net.sourceforge.cobertura.coveragedata.ProjectData;
24  import org.apache.maven.artifact.Artifact;
25  import org.apache.maven.doxia.siterenderer.Renderer;
26  import org.apache.maven.plugin.MojoExecutionException;
27  import org.apache.maven.project.MavenProject;
28  import org.apache.maven.reporting.AbstractMavenReport;
29  import org.apache.maven.reporting.MavenReportException;
30  import org.codehaus.mojo.cobertura.configuration.MaxHeapSizeUtil;
31  import org.codehaus.mojo.cobertura.tasks.CommandLineArguments;
32  import org.codehaus.mojo.cobertura.tasks.ReportTask;
33  
34  import java.io.File;
35  import java.net.URI;
36  import java.util.ArrayList;
37  import java.util.Collections;
38  import java.util.HashMap;
39  import java.util.List;
40  import java.util.Locale;
41  import java.util.Map;
42  import java.util.ResourceBundle;
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  public class CoberturaReportMojo
54      extends AbstractMavenReport
55  {
56      
57  
58  
59  
60  
61  
62      private String format;
63  
64      
65  
66  
67  
68  
69      private String[] formats = new String[]{ "html" };
70  
71      
72  
73  
74  
75  
76  
77      private String encoding;
78  
79      
80  
81  
82  
83  
84      private String maxmem = "64m";
85  
86      
87  
88  
89  
90  
91  
92  
93  
94  
95      private File dataFile;
96  
97      
98  
99  
100 
101 
102 
103 
104     private List<Artifact> pluginClasspathList;
105 
106     
107 
108 
109 
110 
111 
112     private File outputDirectory;
113 
114     
115 
116 
117 
118 
119 
120     private boolean quiet;
121 
122     
123 
124 
125 
126 
127 
128     private boolean aggregate;
129 
130     
131 
132 
133 
134 
135 
136 
137 
138 
139     private boolean omitGplFiles;
140 
141     
142 
143 
144 
145 
146     private Renderer siteRenderer;
147 
148     
149 
150 
151 
152 
153 
154 
155     private List<MavenProject> reactorProjects;
156 
157     
158 
159 
160 
161 
162 
163 
164     private MavenProject project;
165 
166     private Map<MavenProject, List<MavenProject>> projectChildren;
167 
168     private String relDataFileName;
169 
170     private String relAggregateOutputDir;
171 
172     
173 
174 
175 
176 
177     public CoberturaReportMojo()
178     {
179         if ( MaxHeapSizeUtil.getInstance().envHasMavenMaxMemSetting() )
180         {
181             maxmem = MaxHeapSizeUtil.getInstance().getMavenMaxMemSetting();
182         }
183     }
184 
185     
186 
187 
188 
189 
190     public String getName( Locale locale )
191     {
192         return getBundle( locale ).getString( "report.cobertura.name" );
193     }
194 
195     
196 
197 
198 
199 
200     public String getDescription( Locale locale )
201     {
202         return getBundle( locale ).getString( "report.cobertura.description" );
203     }
204 
205     @Override
206     protected String getOutputDirectory()
207     {
208         return outputDirectory.getAbsolutePath();
209     }
210 
211     @Override
212     protected MavenProject getProject()
213     {
214         return project;
215     }
216 
217     @Override
218     protected Renderer getSiteRenderer()
219     {
220         return siteRenderer;
221     }
222 
223     
224 
225 
226 
227 
228 
229 
230     private void executeReportTask( ReportTask task, String outputFormat )
231         throws MavenReportException
232     {
233         task.setOutputFormat( outputFormat );
234 
235         
236         try
237         {
238             task.execute();
239         }
240         catch ( MojoExecutionException e )
241         {
242             
243             
244             getLog().error( "Error in Cobertura Report generation: " + e.getMessage(), e );
245         }
246     }
247 
248     
249 
250 
251     @Override
252     protected void executeReport( Locale locale )
253         throws MavenReportException
254     {
255         if ( canGenerateSimpleReport() )
256         {
257             executeReport( getDataFile(), outputDirectory, getCompileSourceRoots() );
258         }
259 
260         if ( canGenerateAggregateReports() )
261         {
262             executeAggregateReport( locale );
263         }
264     }
265 
266     
267 
268 
269     private void executeAggregateReport( Locale locale )
270         throws MavenReportException
271     {
272         for ( MavenProject proj : reactorProjects )
273         {
274             if ( !isMultiModule( proj ) )
275             {
276                 continue;
277             }
278             executeAggregateReport( locale, proj );
279         }
280     }
281 
282     
283 
284 
285     private void executeAggregateReport( Locale locale, MavenProject curProject )
286         throws MavenReportException
287     {
288         List<MavenProject> children = getAllChildren( curProject );
289 
290         if ( children.isEmpty() )
291         {
292             return;
293         }
294 
295         List<File> serFiles = getOutputFiles( children );
296         if ( serFiles.isEmpty() )
297         {
298             getLog().info( "Not executing aggregate cobertura:report for " + curProject.getName()
299                                + " as no child cobertura data files could not be found" );
300             return;
301         }
302 
303         getLog().info( "Executing aggregate cobertura:report for " + curProject.getName() );
304 
305         ProjectData aggProjectData = new ProjectData();
306         for ( File serFile : serFiles )
307         {
308             ProjectData data = CoverageDataFileHandler.loadCoverageData( serFile );
309             aggProjectData.merge( data );
310         }
311 
312         File aggSerFile = new File( curProject.getBasedir(), relDataFileName );
313         aggSerFile.getAbsoluteFile().getParentFile().mkdirs();
314         getLog().info( "Saving aggregate cobertura information in " + aggSerFile.getAbsolutePath() );
315         CoverageDataFileHandler.saveCoverageData( aggProjectData, aggSerFile );
316 
317         
318         List<String> aggCompileSourceRoots = new ArrayList<String>();
319         for ( MavenProject child : children )
320         {
321             aggCompileSourceRoots.addAll( child.getCompileSourceRoots() );
322         }
323 
324         File reportDir = new File( curProject.getBasedir(), relAggregateOutputDir );
325         reportDir.mkdirs();
326         executeReport( aggSerFile, reportDir, aggCompileSourceRoots );
327     }
328 
329     
330 
331 
332     private void executeReport( File curDataFile, File curOutputDirectory, List<String> curCompileSourceRoots )
333         throws MavenReportException
334     {
335         ReportTask task = new ReportTask();
336 
337         
338         task.setLog( getLog() );
339         task.setPluginClasspathList( pluginClasspathList );
340         task.setQuiet( quiet );
341 
342         
343         task.setMaxmem( maxmem );
344         task.setDataFile( curDataFile );
345         task.setOutputDirectory( curOutputDirectory );
346         task.setCompileSourceRoots( curCompileSourceRoots );
347         task.setSourceEncoding( encoding );
348 
349         CommandLineArguments cmdLineArgs;
350         cmdLineArgs = new CommandLineArguments();
351         cmdLineArgs.setUseCommandsFile( true );
352         task.setCmdLineArgs( cmdLineArgs );
353 
354         if ( format != null )
355         {
356             formats = new String[]{ format };
357         }
358 
359         for ( int i = 0; i < formats.length; i++ )
360         {
361             executeReportTask( task, formats[i] );
362         }
363 
364         removeGplFiles();
365     }
366 
367     
368 
369 
370 
371     private void removeGplFiles()
372         throws MavenReportException
373     {
374         if ( omitGplFiles )
375         {
376             final String[] files =
377                 new String[]{ "js/customsorttypes.js", "js/sortabletable.js", "js/stringbuilder.js" };
378             for ( int i = 0; i < files.length; i++ )
379             {
380                 final File f = new File( outputDirectory, files[i] );
381                 if ( f.exists() )
382                 {
383                     if ( f.delete() )
384                     {
385                         getLog().debug( "Removed GPL licensed file " + f.getPath() );
386                     }
387                     else
388                     {
389                         throw new MavenReportException( "Unable to remove GPL licensed file " + f.getPath() );
390                     }
391                 }
392                 else
393                 {
394                     getLog().info( "GPL licensed file " + f.getPath() + " not found." );
395                 }
396             }
397         }
398     }
399 
400     
401 
402 
403     public String getOutputName()
404     {
405         return "cobertura/index";
406     }
407 
408     @Override
409     public boolean isExternalReport()
410     {
411         return true;
412     }
413 
414     @Override
415     public boolean canGenerateReport()
416     {
417         if ( canGenerateSimpleReport() )
418         {
419             return true;
420         }
421         else
422         {
423             getLog().info( "Not executing cobertura:report as the cobertura data file (" + getDataFile()
424                                + ") could not be found" );
425         }
426 
427         if ( canGenerateAggregateReports() )
428         {
429             return true;
430         }
431 
432         if ( aggregate && isMultiModule( project ) )
433         {
434             
435             
436             
437             return true;
438         }
439         return false;
440     }
441 
442     
443 
444 
445 
446 
447     private boolean canGenerateSimpleReport()
448     {
449         
450 
451 
452 
453         return getDataFile().exists() && getDataFile().isFile();
454     }
455 
456     
457 
458 
459     private boolean canGenerateAggregateReports()
460     {
461         
462         if ( aggregate && isLastProject( project, reactorProjects ) )
463         {
464             buildAggregateInfo();
465 
466             if ( !getOutputFiles( reactorProjects ).isEmpty() )
467             {
468                 return true;
469             }
470         }
471         return false;
472     }
473 
474     
475 
476 
477     @SuppressWarnings( "unchecked" )
478     private List<String> getCompileSourceRoots()
479     {
480         return project.getExecutionProject().getCompileSourceRoots();
481     }
482 
483     @Override
484     public void setReportOutputDirectory( File reportOutputDirectory )
485     {
486         if ( ( reportOutputDirectory != null ) && ( !reportOutputDirectory.getAbsolutePath().endsWith( "cobertura" ) ) )
487         {
488             this.outputDirectory = new File( reportOutputDirectory, "cobertura" );
489         }
490         else
491         {
492             this.outputDirectory = reportOutputDirectory;
493         }
494     }
495 
496     
497 
498 
499 
500 
501 
502     private ResourceBundle getBundle( Locale locale )
503     {
504         return ResourceBundle.getBundle( "cobertura-report", locale );
505     }
506 
507     
508 
509 
510 
511 
512 
513 
514     private boolean isLastProject( MavenProject project, List<MavenProject> mavenProjectList )
515     {
516         return project.equals( mavenProjectList.get( mavenProjectList.size() - 1 ) );
517     }
518 
519     
520 
521 
522 
523 
524 
525     private boolean isMultiModule( MavenProject mavenProject )
526     {
527         return "pom".equals( mavenProject.getPackaging() );
528     }
529 
530     
531 
532 
533     private void buildAggregateInfo()
534     {
535         if ( projectChildren != null )
536         {
537             
538             return;
539         }
540 
541         
542         projectChildren = new HashMap<MavenProject, List<MavenProject>>();
543         for ( MavenProject proj : reactorProjects )
544         {
545             List<MavenProject> depList = projectChildren.get( proj.getParent() );
546             if ( depList == null )
547             {
548                 depList = new ArrayList<MavenProject>();
549                 projectChildren.put( proj.getParent(), depList );
550             }
551             depList.add( proj );
552         }
553 
554         
555         relDataFileName = relativize( project.getBasedir(), getDataFile() );
556         if ( relDataFileName == null )
557         {
558             getLog().warn( "Could not determine relative data file name, defaulting to 'cobertura/cobertura.ser'" );
559             relDataFileName = "cobertura/cobertura.ser";
560         }
561         relAggregateOutputDir = relativize( project.getBasedir(), outputDirectory );
562         if ( relAggregateOutputDir == null )
563         {
564             getLog().warn( "Could not determine relative output dir name, defaulting to 'cobertura'" );
565             relAggregateOutputDir = "cobertura";
566         }
567     }
568 
569     
570 
571 
572     private List<MavenProject> getAllChildren( MavenProject parentProject )
573     {
574         List<MavenProject> children = projectChildren.get( parentProject );
575         if ( children == null )
576         {
577             return Collections.emptyList();
578         }
579 
580         List<MavenProject> result = new ArrayList<MavenProject>();
581         for ( MavenProject child : children )
582         {
583             if ( isMultiModule( child ) )
584             {
585                 result.addAll( getAllChildren( child ) );
586             }
587             else
588             {
589                 result.add( child );
590             }
591         }
592         return result;
593     }
594 
595     
596 
597 
598     private List<File> getOutputFiles( List<MavenProject> projects )
599     {
600         List<File> files = new ArrayList<File>();
601         for ( MavenProject proj : projects )
602         {
603             if ( isMultiModule( proj ) )
604             {
605                 continue;
606             }
607             File outputFile = new File( proj.getBasedir(), relDataFileName );
608             if ( outputFile.exists() )
609             {
610                 files.add( outputFile );
611             }
612         }
613         return files;
614     }
615 
616     
617 
618 
619     private String relativize( File parentFile, File childFile )
620     {
621         try
622         {
623             URI parentURI = parentFile.getCanonicalFile().toURI().normalize();
624             URI childURI = childFile.getCanonicalFile().toURI().normalize();
625 
626             URI relativeURI = parentURI.relativize( childURI );
627             if ( relativeURI.isAbsolute() )
628             {
629                 
630                 return null;
631             }
632             String relativePath = relativeURI.getPath();
633             if ( File.separatorChar != '/' )
634             {
635                 relativePath = relativePath.replace( '/', File.separatorChar );
636             }
637             return relativePath;
638         }
639         catch ( Exception e )
640         {
641             getLog().warn( "Failed relativizing " + childFile + " to " + parentFile, e );
642         }
643         return null;
644     }
645 
646     
647 
648 
649 
650 
651     private File getDataFile()
652     {
653         return dataFile;
654     }
655 }