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.IOException;
21  import java.io.InputStream;
22  import java.net.URL;
23  import java.util.Date;
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Locale;
28  import java.util.Map;
29  import java.util.ResourceBundle;
30  
31  import org.apache.maven.artifact.repository.ArtifactRepository;
32  import org.apache.maven.plugin.MojoExecutionException;
33  import org.apache.maven.project.MavenProject;
34  import org.apache.maven.project.MavenProjectBuilder;
35  import org.apache.maven.reporting.AbstractMavenReport;
36  import org.apache.maven.reporting.MavenReportException;
37  
38  import org.codehaus.doxia.site.renderer.SiteRenderer;
39  import org.codehaus.mojo.dashboard.report.plugin.beans.DashBoardMavenProject;
40  import org.codehaus.mojo.dashboard.report.plugin.configuration.Configuration;
41  import org.codehaus.mojo.dashboard.report.plugin.configuration.ConfigurationService;
42  import org.codehaus.mojo.dashboard.report.plugin.configuration.ConfigurationServiceException;
43  import org.codehaus.mojo.dashboard.report.plugin.configuration.IConfigurationService;
44  import org.codehaus.mojo.dashboard.report.plugin.hibernate.HibernateService;
45  import org.codehaus.plexus.resource.ResourceManager;
46  import org.codehaus.plexus.resource.loader.FileResourceCreationException;
47  import org.codehaus.plexus.resource.loader.FileResourceLoader;
48  import org.codehaus.plexus.util.FileUtils;
49  import org.codehaus.plexus.util.IOUtil;
50  import org.codehaus.plexus.util.StringInputStream;
51  import org.codehaus.plexus.util.StringUtils;
52  
53  /**
54   * A Dashboard report which aggregates all other report results.
55   *
56   * @author <a href="dvicente72@gmail.com">David Vicente</a>
57   * @goal dashboard
58   */
59  
60  public class DashBoardReportMojo extends AbstractMavenReport
61  {
62      /**
63       * The maven project
64       *
65       * @parameter expression="${project}"
66       * @readonly
67       */
68      private MavenProject project;
69  
70      /**
71       * Directory containing The generated DashBoard report Datafile "dashboard-report.xml".
72       *
73       * @parameter expression="${project.reporting.outputDirectory}"
74       * @required
75       */
76      private File outputDirectory;
77  
78      /**
79       * Site Renderer
80       *
81       * @parameter expression="${component.org.codehaus.doxia.site.renderer.SiteRenderer}"
82       * @readonly
83       */
84      private SiteRenderer siteRenderer;
85  
86      /**
87       * <p>
88       * The generated DashBoard report Datafile.
89       * </p>
90       *
91       * @parameter expression="dashboard-report.xml"
92       * @readonly
93       */
94      protected String dashboardDataFile;
95  
96      /**
97       * The filename to use for the report.
98       *
99       * @parameter expression="dashboard-report"
100      * @readonly
101      */
102     private String outputName;
103 
104     /**
105      * The local repository.
106      *
107      * @parameter expression="${localRepository}"
108      * @readonly
109      */
110     protected ArtifactRepository localRepository;
111 
112     /**
113      * number of XRef JDepend/Cobertura packages to export in dashboard summary page
114      *
115      * @parameter default-value="10"
116      */
117     private int nbExportedPackagesSummary;
118 
119     /**
120      * Project builder
121      *
122      * @component
123      */
124     protected MavenProjectBuilder mavenProjectBuilder;
125 
126     /**
127      * Hibernate Service
128      *
129      * @component
130      */
131     protected HibernateService hibernateService;
132 
133     /**
134      * Hibernate dialect
135      *
136      * @parameter expression="${dialect}"
137      */
138     protected String dialect;
139 
140     /**
141      * Hibernate driver class
142      *
143      * @parameter expression="${driverClass}"
144      */
145     protected String driverClass;
146 
147     /**
148      * Hibernate connection URL
149      *
150      * @parameter expression="${connectionUrl}"
151      */
152     protected String connectionUrl;
153 
154     /**
155      * Hibernate database username
156      *
157      * @parameter expression="${username}"
158      */
159     protected String username;
160 
161     /**
162      * Hibernate database password
163      *
164      * @parameter expression="${password}"
165      */
166     protected String password;
167 
168     /**
169      * <p>
170      * Specifies the location of the XML configuration to use.
171      * </p>
172      * <p>
173      * Potential values are a filesystem path, a URL, or a classpath resource. This parameter expects that the contents
174      * of the location conform to the xml format (<a href="http://mojo.codehaus.org/dashboard-maven-plugin/">Dashboard
175      * Maven plugin</a>) configuration .
176      * </p>
177      * <p>
178      * This parameter is resolved as resource, URL, then file. If successfully resolved, the contents of the
179      * configuration is copied into the <code>${project.build.directory}/default-dashboard-config.xml</code> file
180      * before being passed to dashboard as a configuration.
181      * </p>
182      * <p>
183      * There are 1 predefined config.
184      * </p>
185      * <ul>
186      * <li><code>config/default-dashboard-config.xml</code>: default config.</li>
187      * </ul>
188      *
189      * @parameter expression="${configLocation}" default-value="config/default-dashboard-config.xml"
190      */
191     private String configLocation;
192 
193     /**
194      * @component
195      * @required
196      * @readonly
197      */
198     private ResourceManager locator;
199 
200     /**
201      * Used to generate a dashboard report as Maven 1, only for multi-modules project. It also merges the 2 reports
202      * (Summary and detailled) as only one.
203      *
204      * @parameter expression="${m1LikeRendering}" default-value="false"
205      */
206     private boolean m1LikeRendering;
207 
208     /**
209      * This parameter is used to keep the version as a discriminant criteria of a project. If set as "true", the data of
210      * reports will be specific to this version of a project. If set as "false", the data of reports will be associated
211      * with the project regardless of its version.
212      *
213      * @parameter expression="${keepVersionAsDiscriminantCriteria}" default-value="true"
214      */
215     private boolean keepVersionAsDiscriminantCriteria;
216 
217     /**
218      * <p>
219      * This parameter is used to disable the graphics generation to avoid unexpected error when X11 window server not
220      * installed on Linux/Unix machine.
221      * </p>
222      * <p>
223      * <ul>
224      * <li>If set as "true" or not set (default value is used) , all graphics will be generated.</li>
225      * <li>> If set as "false", the Dashboard won't generate graphics for summary and detailled reports and the
226      * historic report will be disabled.</li>
227      * </ul>
228      * </p>
229      *
230      * @parameter expression="${generateGraphs}" default-value="true"
231      */
232     private boolean generateGraphs;
233 
234     private DashBoardUtils dashBoardUtils;
235 
236     private Locale locale;
237 
238     protected boolean isPropHibernateSet = false;
239 
240     /**
241      *
242      */
243     protected void executeReport( Locale arg0 ) throws MavenReportException
244     {
245         this.locale = arg0;
246 
247         // Thanks to the Checkstyle Maven plugin team for this part of code.
248         this.locator.addSearchPath( FileResourceLoader.ID, this.project.getFile().getParentFile().getAbsolutePath() );
249         this.locator.addSearchPath( "url", "" );
250         this.locator.setOutputDirectory( new File( this.project.getBuild().getDirectory() ) );
251         // Thanks end.
252         this.getLog().info( "MultiReportMojo project = " + this.project.getName() );
253         this.getLog().info( "MultiReportMojo nb modules = " + this.project.getModules().size() );
254         this.getLog().info( "MultiReportMojo base directory = " + this.project.getBasedir() );
255         this.getLog().info( "MultiReportMojo output directory = " + this.outputDirectory );
256         this.getLog().info( "MultiReportMojo report output directory = " + this.getReportOutputDirectory() );
257         this.getLog().info(
258                             "MultiReportMojo project language = "
259                                             + this.project.getArtifact().getArtifactHandler().getLanguage() );
260         this.copyStaticResources();
261         this.dashBoardUtils =
262             DashBoardUtils.getInstance( this.getLog(), this.mavenProjectBuilder, this.localRepository, false );
263         this.isPropHibernateSet = this.isDBAvailable();
264         if ( this.isPropHibernateSet )
265         {
266             this.configureHibernateDriver();
267         }
268         boolean canGenerate = this.canGenerateReport();
269         if ( canGenerate )
270         {
271             DashBoardMavenProject mavenProject = null;
272 
273             if ( this.isPropHibernateSet )
274             {
275                 this.configureHibernateDriver();
276 
277             }
278             Date generatedDate = new Date( System.currentTimeMillis() );
279 
280             mavenProject =
281                 this.dashBoardUtils.getDashBoardMavenProject( this.project, this.dashboardDataFile, generatedDate );
282             this.dashBoardUtils.saveXMLDashBoardReport( this.project, mavenProject, this.dashboardDataFile );
283 
284             if ( mavenProject != null )
285             {
286                 boolean isSummary = false;
287                 if ( mavenProject.getModules() != null && !mavenProject.getModules().isEmpty() )
288                 {
289                     isSummary = true;
290                 }
291 
292                 AbstractDashBoardGenerator reportGenerator = null;
293 
294                 if ( this.project.getModules() != null && this.project.getModules().size() > 0 && this.m1LikeRendering )
295                 {
296                     reportGenerator =
297                         new DashBoardMaven1ReportGenerator( mavenProject, this.isPropHibernateSet, this.getLog() );
298                 }
299                 else
300                 {
301                     reportGenerator =
302                         new DashBoardReportGenerator( mavenProject, isSummary, this.isPropHibernateSet,
303                                                       this.generateGraphs, this.getLog() );
304                 }
305                 reportGenerator.setImagesPath( this.getReportOutputDirectory() + "/images" );
306                 reportGenerator.setNbExportedPackagesSummary( this.nbExportedPackagesSummary );
307                 reportGenerator.doGenerateReport( this.getBundle( this.locale ), this.getSink() );
308                 if ( this.isPropHibernateSet )
309                 {
310                     // Thanks to the Checkstyle Maven plugin team for this part of code.
311                     ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
312                     Configuration dashConfig = null;
313                     try
314                     {
315                         // dashboard will always use the context classloader in order
316                         // to load resources (xml schema)
317                         ClassLoader dashboardClassLoader = DashBoardUtils.class.getClassLoader();
318                         Thread.currentThread().setContextClassLoader( dashboardClassLoader );
319 
320                         String configFile = this.getConfigFile();
321                         this.getLog().info( "getConfigFile() = " + configFile );
322                         IConfigurationService configService = new ConfigurationService( configFile );
323 
324                         dashConfig = configService.getConfiguration();
325 
326                         if ( !configService.isValidConfig() )
327                         {
328                             List warningMsg = configService.getWarningMessages();
329 
330                             Iterator iter = warningMsg.iterator();
331                             while ( iter.hasNext() )
332                             {
333                                 this.getLog().error( (String) iter.next() );
334                             }
335                             throw new MavenReportException(
336                                                             "The maven-dashboard-config.xml is not valid. see error messages above or see the maven-dashboard-config.xsd file." );
337                         }
338 
339                     }
340                     catch ( ConfigurationServiceException e )
341                     {
342                         this.getLog().error( "DashBoardHistoricReportMojo executeReport() failed.", e );
343                         throw new MavenReportException(
344                                                         "The maven-dashboard-config.xml is not valid. see error messages above or see the maven-dashboard-config.xsd file." );
345                     }
346                     catch ( Exception e )
347                     {
348                         this.getLog().error( "DashBoardHistoricReportMojo executeReport() failed.", e );
349                         throw new MavenReportException(
350                                                         "The maven-dashboard-config.xml is not valid. see error messages above or see the maven-dashboard-config.xsd file." );
351                     }
352                     finally
353                     {
354                         // be sure to restore original context classloader
355                         Thread.currentThread().setContextClassLoader( currentClassLoader );
356                     }
357                     // Thanks end.
358                     try
359                     {
360                         if ( dashConfig != null )
361                         {
362                             org.codehaus.doxia.module.xhtml.XhtmlSink sink =
363                                 this.getSiteRenderer().createSink( this.getReportOutputDirectory(),
364                                                                    this.getOutputName() + "-historic.html",
365                                                                    this.getReportOutputDirectory().getPath(),
366                                                                    this.getSiteDescriptor(), "maven" );
367                             DashBoardHistoricReportGenerator histoReportGenerator =
368                                 new DashBoardHistoricReportGenerator( mavenProject, this.hibernateService, dashConfig,
369                                                                       this.keepVersionAsDiscriminantCriteria,
370                                                                       this.generateGraphs, this.getLog() );
371                             histoReportGenerator.setImagesPath( this.getReportOutputDirectory() + "/images" );
372                             histoReportGenerator.doGenerateReport( this.getBundle( this.locale ), sink );
373                         }
374                     }
375                     catch ( MojoExecutionException e )
376                     {
377                         this.getLog().error( "DashBoardHistoricReportMojo executeReport() failed.", e );
378                     }
379                     catch ( Exception e )
380                     {
381                         this.getLog().error( "DashBoardHistoricReportMojo executeReport() failed.", e );
382                     }
383                 }
384                 if ( this.project.getModules() != null && this.project.getModules().size() > 0 && !this.m1LikeRendering )
385                 {
386                     try
387                     {
388                         org.codehaus.doxia.module.xhtml.XhtmlSink sink =
389                             this.getSiteRenderer().createSink( this.getReportOutputDirectory(),
390                                                                this.getOutputName() + "-details.html",
391                                                                this.getReportOutputDirectory().getPath(),
392                                                                this.getSiteDescriptor(), "maven" );
393                         DashBoardMultiReportGenerator detailReportGenerator =
394                             new DashBoardMultiReportGenerator( mavenProject, this.isPropHibernateSet,
395                                                                this.generateGraphs, this.getLog() );
396                         detailReportGenerator.setImagesPath( this.getReportOutputDirectory() + "/images" );
397                         detailReportGenerator.doGenerateReport( this.getBundle( this.locale ), sink );
398                     }
399                     catch ( MojoExecutionException e )
400                     {
401                         this.getLog().error( "DashBoardReportMojo executeReport() failed.", e );
402                     }
403                     catch ( Exception e )
404                     {
405                         this.getLog().error( "DashBoardReportMojo executeReport() failed.", e );
406                     }
407                 }
408             }
409         }
410 
411     }
412 
413     /**
414      *
415      */
416     protected String getOutputDirectory()
417     {
418         return this.outputDirectory.getPath();
419     }
420 
421     /**
422      *
423      */
424     protected MavenProject getProject()
425     {
426         return this.project;
427     }
428 
429     protected SiteRenderer getSiteRenderer()
430     {
431         return this.siteRenderer;
432     }
433 
434     public String getDescription( Locale locale )
435     {
436         String description = "";
437         if ( this.project.getModules().size() > 0 )
438         {
439             description = this.getBundle( locale ).getString( "dashboard.multireport.description" );
440         }
441         else
442         {
443             description = this.getBundle( locale ).getString( "dashboard.report.description" );
444         }
445         return description;
446     }
447 
448     public String getName( Locale locale )
449     {
450         String name = "";
451         if ( this.project.getModules().size() > 0 )
452         {
453             name = this.getBundle( locale ).getString( "dashboard.multireport.name" );
454         }
455         else
456         {
457             name = this.getBundle( locale ).getString( "dashboard.report.name" );
458         }
459         return name;
460     }
461 
462     public String getOutputName()
463     {
464         return this.outputName;
465     }
466 
467     public ResourceBundle getBundle( Locale locale )
468     {
469         return ResourceBundle.getBundle( "dashboard-report-plugin", locale, this.getClass().getClassLoader() );
470     }
471 
472     public boolean usePageLinkBar()
473     {
474         return true;
475     }
476 
477     private InputStream getSiteDescriptor() throws MojoExecutionException
478     {
479         String siteDescriptorContent = "";
480         try
481         {
482             siteDescriptorContent = IOUtil.toString( this.getClass().getResourceAsStream( "/default-report.xml" ) );
483         }
484         catch ( IOException e )
485         {
486             throw new MojoExecutionException( "The site descriptor cannot be read!", e );
487         }
488         Map props = new HashMap();
489         props.put( "reports", this.getReportsMenu() );
490         if ( this.getProject().getName() != null )
491         {
492             props.put( "project.name", this.getProject().getName() );
493         }
494         else
495         {
496             props.put( "project.name", "NO_PROJECT_NAME_SET" );
497         }
498         if ( this.getProject().getUrl() != null )
499         {
500             props.put( "project.url", this.getProject().getUrl() );
501         }
502         else
503         {
504             props.put( "project.url", "NO_PROJECT_URL_SET" );
505         }
506         siteDescriptorContent = StringUtils.interpolate( siteDescriptorContent, props );
507         return new StringInputStream( siteDescriptorContent );
508     }
509 
510     private String getReportsMenu()
511     {
512         StringBuffer buffer = new StringBuffer();
513         buffer.append( "<menu name=\"Project Reports\">\n" );
514         buffer.append( "  <item name=\"Root\" href=\"/project-reports.html\"/>\n" );
515         buffer.append( "  <item name=\"" + this.getName( this.locale ) + "\" href=\"/" + this.getOutputName()
516                         + ".html\"/>\n" );
517         buffer.append( "</menu>\n" );
518         return buffer.toString();
519     }
520 
521     public boolean canGenerateReport()
522     {
523         if ( this.project.getCollectedProjects().size() < this.project.getModules().size() )
524         {
525             this.getLog().info( "DashBoardReportMojo: Not recursive into sub-projects - skipping report." );
526             return false;
527         }
528         return true;
529     }
530 
531     protected void configureHibernateDriver()
532     {
533         this.hibernateService.setDialect( this.dialect );
534         this.hibernateService.setDriverClass( this.driverClass );
535         this.hibernateService.setConnectionUrl( this.connectionUrl );
536         this.hibernateService.setUsername( this.username );
537         this.hibernateService.setPassword( this.password );
538     }
539 
540     protected boolean isDBAvailable()
541     {
542         boolean isDBAvailable = false;
543         if ( ( this.dialect != null && this.dialect.length() > 0 )
544                         && ( this.driverClass != null && this.driverClass.length() > 0 )
545                         && ( this.connectionUrl != null && this.connectionUrl.length() > 0 )
546                         && ( this.username != null && this.username.length() > 0 )
547                         && ( this.password != null && this.password.length() > 0 ) )
548         {
549             isDBAvailable = true;
550         }
551         return isDBAvailable;
552     }
553 
554     /**
555      * @return
556      * @throws MavenReportException
557      */
558     private String getConfigFile() throws MavenReportException
559     {
560         // Thanks to the Checkstyle Maven plugin team for this part of code.
561         try
562         {
563             this.getLog().info( "getConfigFile() = " + this.configLocation );
564 
565             File configFile = this.locator.getResourceAsFile( this.configLocation, "default-dashboard-config.xml" );
566 
567             if ( configFile == null )
568             {
569                 throw new MavenReportException( "Unable to process dashboard config location: " + this.configLocation );
570             }
571             return configFile.getAbsolutePath();
572         }
573         catch ( org.codehaus.plexus.resource.loader.ResourceNotFoundException e )
574         {
575             throw new MavenReportException( "Unable to find dashboard configuration file at location "
576                             + this.configLocation, e );
577         }
578         catch ( FileResourceCreationException e )
579         {
580             throw new MavenReportException( "Unable to process dashboard configuration file location "
581                             + this.configLocation, e );
582         }
583         // Thanks end.
584     }
585 
586     /**
587      * Thanks to the maven-changes-plugin team for this part of code.
588      *
589      * @throws MavenReportException
590      */
591     private void copyStaticResources() throws MavenReportException
592     {
593         String resourceNames[] =
594             { "images/down.gif", "images/Down-green-full.jpg", "images/Down-red-full.jpg",
595                 "images/Down-orange-full.jpg", "images/next.gif", "images/previous.gif", "images/up.gif",
596                 "images/Stable-green-full.jpg", "images/Stable-red-full.jpg", "images/Stable-orange-full.jpg",
597                 "images/Up-green-full.jpg", "images/Up-red-full.jpg", "images/Up-orange-full.jpg",
598                 "css/dashboard.css", "css/dashboard2.css", "css/dashboard2IE.css" };
599         try
600         {
601 
602             this.getLog().debug( "Copying static resources." );
603             for ( int i = 0; i < resourceNames.length; i++ )
604             {
605                 URL url = this.getClass().getClassLoader().getResource( resourceNames[i] );
606                 FileUtils.copyURLToFile( url, new File( this.getReportOutputDirectory(), resourceNames[i] ) );
607             }
608         }
609         catch ( IOException e )
610         {
611             throw new MavenReportException( "Unable to copy static resources." );
612         }
613     }
614 }