View Javadoc

1   package org.apache.maven.report.projectinfo;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.artifact.Artifact;
23  import org.apache.maven.artifact.factory.ArtifactFactory;
24  import org.apache.maven.artifact.repository.ArtifactRepository;
25  import org.apache.maven.artifact.resolver.ArtifactResolver;
26  import org.apache.maven.doxia.sink.render.RenderingContext;
27  import org.apache.maven.doxia.site.decoration.Body;
28  import org.apache.maven.doxia.site.decoration.DecorationModel;
29  import org.apache.maven.doxia.siterenderer.Renderer;
30  import org.apache.maven.doxia.siterenderer.RendererException;
31  import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
32  import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
33  import org.apache.maven.doxia.tools.SiteTool;
34  import org.apache.maven.doxia.tools.SiteToolException;
35  import org.apache.maven.plugin.MojoExecutionException;
36  import org.apache.maven.plugins.annotations.Component;
37  import org.apache.maven.plugins.annotations.Parameter;
38  import org.apache.maven.project.MavenProject;
39  import org.apache.maven.reporting.AbstractMavenReport;
40  import org.apache.maven.reporting.MavenReportException;
41  import org.apache.maven.settings.Settings;
42  import org.codehaus.plexus.i18n.I18N;
43  import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
44  import org.codehaus.plexus.interpolation.InterpolationException;
45  import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
46  import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
47  import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
48  import org.codehaus.plexus.util.IOUtil;
49  
50  
51  import java.io.File;
52  import java.io.FileOutputStream;
53  import java.io.IOException;
54  import java.io.OutputStreamWriter;
55  import java.io.Writer;
56  import java.net.MalformedURLException;
57  import java.net.URL;
58  import java.net.URLClassLoader;
59  import java.text.MessageFormat;
60  import java.util.HashMap;
61  import java.util.List;
62  import java.util.Locale;
63  import java.util.Map;
64  import java.util.MissingResourceException;
65  import java.util.ResourceBundle;
66  
67  /**
68   * Base class with the things that should be in AbstractMavenReport anyway.
69   *
70   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
71   * @version $Id: AbstractProjectInfoReport.java 1367255 2012-07-30 20:01:21Z hboutemy $
72   * @since 2.0
73   */
74  public abstract class AbstractProjectInfoReport
75      extends AbstractMavenReport
76  {
77      // ----------------------------------------------------------------------
78      // Mojo components
79      // ----------------------------------------------------------------------
80  
81      /**
82       * SiteTool component.
83       *
84       * @since 2.1
85       */
86      @Component
87      protected SiteTool siteTool;
88  
89      /**
90       * Doxia Site Renderer component.
91       */
92      @Component
93      protected Renderer siteRenderer;
94  
95      /**
96       * Artifact Resolver component.
97       */
98      @Component
99      protected ArtifactResolver resolver;
100 
101     /**
102      * Artifact Factory component.
103      */
104     @Component
105     protected ArtifactFactory factory;
106 
107     /**
108      * Internationalization component, could support also custom bundle using {@link #customBundle}.
109      */
110     @Component
111     private I18N i18n;
112 
113     // ----------------------------------------------------------------------
114     // Mojo parameters
115     // ----------------------------------------------------------------------
116 
117     /**
118      * The output directory for the report. Note that this parameter is only evaluated if the goal is run directly from
119      * the command line. If the goal is run indirectly as part of a site generation, the output directory configured in
120      * the Maven Site Plugin is used instead.
121      */
122     @Parameter( property = "project.reporting.outputDirectory", required = true )
123     protected File outputDirectory;
124 
125     /**
126      * The Maven Project.
127      */
128     @Component
129     protected MavenProject project;
130 
131     /**
132      * Local Repository.
133      */
134     @Parameter( property = "localRepository", required = true, readonly = true )
135     protected ArtifactRepository localRepository;
136 
137     /**
138      * Remote repositories used for the project.
139      *
140      * @since 2.1
141      */
142     @Parameter( property = "project.remoteArtifactRepositories" )
143     protected List<ArtifactRepository> remoteRepositories;
144 
145     /**
146      * The current user system settings for use in Maven.
147      *
148      * @since 2.3
149      */
150     @Component
151     protected Settings settings;
152 
153     /**
154      * Path for a custom bundle instead of using the default one. <br/>
155      * Using this field, you could change the texts in the generated reports.
156      *
157      * @since 2.3
158      */
159     @Parameter( defaultValue = "${project.basedir}/src/site/custom/project-info-report.properties" )
160     protected String customBundle;
161 
162     // ----------------------------------------------------------------------
163     // Public methods
164     // ----------------------------------------------------------------------
165 
166     @Override
167     public void execute()
168         throws MojoExecutionException
169     {
170         if ( !canGenerateReport() )
171         {
172             return;
173         }
174 
175         // TODO: push to a helper? Could still be improved by taking more of the site information from the site plugin
176         Writer writer = null;
177         try
178         {
179             String filename = getOutputName() + ".html";
180 
181             DecorationModel model = new DecorationModel();
182             model.setBody( new Body() );
183 
184             Map<String, Object> attributes = new HashMap<String, Object>();
185             attributes.put( "outputEncoding", "UTF-8" );
186             attributes.put( "project", project );
187 
188             Locale locale = Locale.getDefault();
189             Artifact defaultSkin =
190                 siteTool.getDefaultSkinArtifact( localRepository, project.getRemoteArtifactRepositories() );
191 
192             SiteRenderingContext siteContext =
193                 siteRenderer.createContextForSkin( defaultSkin.getFile(), attributes, model, getName( locale ), locale );
194 
195             RenderingContext context = new RenderingContext( outputDirectory, filename );
196 
197             SiteRendererSink sink = new SiteRendererSink( context );
198 
199             generate( sink, null, locale );
200 
201             outputDirectory.mkdirs();
202 
203             writer = new OutputStreamWriter( new FileOutputStream( new File( outputDirectory, filename ) ), "UTF-8" );
204 
205             siteRenderer.generateDocument( writer, sink, siteContext );
206 
207             siteRenderer.copyResources( siteContext, new File( project.getBasedir(), "src/site/resources" ),
208                                         outputDirectory );
209         }
210         catch ( RendererException e )
211         {
212             throw new MojoExecutionException( "An error has occurred in " + getName( Locale.ENGLISH )
213                 + " report generation.", e );
214         }
215         catch ( IOException e )
216         {
217             throw new MojoExecutionException( "An error has occurred in " + getName( Locale.ENGLISH )
218                 + " report generation.", e );
219         }
220         catch ( SiteToolException e )
221         {
222             throw new MojoExecutionException( "An error has occurred in " + getName( Locale.ENGLISH )
223                 + " report generation.", e );
224         }
225         catch ( MavenReportException e )
226         {
227             throw new MojoExecutionException( "An error has occurred in " + getName( Locale.ENGLISH )
228                 + " report generation.", e );
229         }
230         finally
231         {
232             IOUtil.close( writer );
233         }
234     }
235 
236     @Override
237     public String getCategoryName()
238     {
239         return CATEGORY_PROJECT_INFORMATION;
240     }
241 
242     // ----------------------------------------------------------------------
243     // Protected methods
244     // ----------------------------------------------------------------------
245 
246     @Override
247     protected String getOutputDirectory()
248     {
249         return outputDirectory.getAbsolutePath();
250     }
251 
252     @Override
253     public File getReportOutputDirectory()
254     {
255         return outputDirectory;
256     }
257 
258     @Override
259     public void setReportOutputDirectory( File reportOutputDirectory )
260     {
261         this.outputDirectory = reportOutputDirectory;
262     }
263 
264     @Override
265     protected MavenProject getProject()
266     {
267         return project;
268     }
269 
270     @Override
271     protected Renderer getSiteRenderer()
272     {
273         return siteRenderer;
274     }
275 
276     protected String getI18nString( Locale locale, String key )
277     {
278         return getI18N( locale ).getString( "project-info-report", locale, "report." + getI18Nsection() + '.' + key );
279     }
280 
281     protected I18N getI18N( Locale locale )
282     {
283         if ( customBundle != null )
284         {
285             File customBundleFile = new File( customBundle );
286             if ( customBundleFile.isFile() && customBundleFile.getName().endsWith( ".properties" ) )
287             {
288                 if ( !i18n.getClass().isAssignableFrom( CustomI18N.class ) )
289                 {
290                     // first load
291                     i18n = new CustomI18N( project, settings, customBundleFile, locale, i18n );
292                 }
293                 else if ( !i18n.getDefaultLanguage().equals( locale.getLanguage() ) )
294                 {
295                     i18n = new CustomI18N( project, settings, customBundleFile, locale, i18n );
296                 }
297             }
298         }
299 
300         return i18n;
301     }
302 
303     protected abstract String getI18Nsection();
304 
305     /** {@inheritDoc} */
306     public String getName( Locale locale )
307     {
308         return getI18nString( locale, "name" );
309     }
310 
311     /** {@inheritDoc} */
312     public String getDescription( Locale locale )
313     {
314         return getI18nString( locale, "description" );
315     }
316 
317     private static class CustomI18N
318         implements I18N
319     {
320         private final MavenProject project;
321 
322         private final Settings settings;
323 
324         private final String bundleName;
325 
326         private final Locale locale;
327 
328         private final I18N i18nOriginal;
329 
330         private ResourceBundle bundle;
331 
332         private final static Object[] NO_ARGS = new Object[0];
333 
334         public CustomI18N( MavenProject project, Settings settings, File customBundleFile, Locale locale,
335                            I18N i18nOriginal )
336         {
337             super();
338             this.project = project;
339             this.settings = settings;
340             this.locale = locale;
341             this.i18nOriginal = i18nOriginal;
342             this.bundleName =
343                 customBundleFile.getName().substring( 0, customBundleFile.getName().indexOf( ".properties" ) );
344 
345             URLClassLoader classLoader = null;
346             try
347             {
348                 classLoader = new URLClassLoader( new URL[] { customBundleFile.getParentFile().toURI().toURL() } );
349             }
350             catch ( MalformedURLException e )
351             {
352             }
353 
354             this.bundle = ResourceBundle.getBundle( this.bundleName, locale, classLoader );
355             if ( !this.bundle.getLocale().getLanguage().equals( locale.getLanguage() ) )
356             {
357                 this.bundle = ResourceBundle.getBundle( this.bundleName, Locale.getDefault(), classLoader );
358             }
359         }
360 
361         /** {@inheritDoc} */
362         public String getDefaultLanguage()
363         {
364             return locale.getLanguage();
365         }
366 
367         /** {@inheritDoc} */
368         public String getDefaultCountry()
369         {
370             return locale.getCountry();
371         }
372 
373         /** {@inheritDoc} */
374         public String getDefaultBundleName()
375         {
376             return bundleName;
377         }
378 
379         /** {@inheritDoc} */
380         public String[] getBundleNames()
381         {
382             return new String[] { bundleName };
383         }
384 
385         /** {@inheritDoc} */
386         public ResourceBundle getBundle()
387         {
388             return bundle;
389         }
390 
391         /** {@inheritDoc} */
392         public ResourceBundle getBundle( String bundleName )
393         {
394             return bundle;
395         }
396 
397         /** {@inheritDoc} */
398         public ResourceBundle getBundle( String bundleName, String languageHeader )
399         {
400             return bundle;
401         }
402 
403         /** {@inheritDoc} */
404         public ResourceBundle getBundle( String bundleName, Locale locale )
405         {
406             return bundle;
407         }
408 
409         /** {@inheritDoc} */
410         public Locale getLocale( String languageHeader )
411         {
412             return new Locale( languageHeader );
413         }
414 
415         /** {@inheritDoc} */
416         public String getString( String key )
417         {
418             return getString( bundleName, locale, key );
419         }
420 
421         /** {@inheritDoc} */
422         public String getString( String key, Locale locale )
423         {
424             return getString( bundleName, locale, key );
425         }
426 
427         /** {@inheritDoc} */
428         public String getString( String bundleName, Locale locale, String key )
429         {
430             String value;
431 
432             if ( locale == null )
433             {
434                 locale = getLocale( null );
435             }
436 
437             ResourceBundle rb = getBundle( bundleName, locale );
438             value = getStringOrNull( rb, key );
439 
440             if ( value == null )
441             {
442                 // try to load default
443                 value = i18nOriginal.getString( bundleName, locale, key );
444             }
445 
446             if ( value.indexOf( "${" ) < 0 )
447             {
448                 return value;
449             }
450 
451             final RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
452             try
453             {
454                 interpolator.addValueSource( new EnvarBasedValueSource() );
455             }
456             catch ( final IOException e )
457             {
458             }
459 
460             interpolator.addValueSource( new PropertiesBasedValueSource( System.getProperties() ) );
461             interpolator.addValueSource( new PropertiesBasedValueSource( project.getProperties() ) );
462             interpolator.addValueSource( new PrefixedObjectValueSource( "project", project ) );
463             interpolator.addValueSource( new PrefixedObjectValueSource( "pom", project ) );
464             interpolator.addValueSource( new PrefixedObjectValueSource( "settings", settings ) );
465 
466             try
467             {
468                 value = interpolator.interpolate( value );
469             }
470             catch ( final InterpolationException e )
471             {
472             }
473 
474             return value;
475         }
476 
477         /** {@inheritDoc} */
478         public String format( String key, Object arg1 )
479         {
480             return format( bundleName, locale, key, new Object[] { arg1 } );
481         }
482 
483         /** {@inheritDoc} */
484         public String format( String key, Object arg1, Object arg2 )
485         {
486             return format( bundleName, locale, key, new Object[] { arg1, arg2 } );
487         }
488 
489         /** {@inheritDoc} */
490         public String format( String bundleName, Locale locale, String key, Object arg1 )
491         {
492             return format( bundleName, locale, key, new Object[] { arg1 } );
493         }
494 
495         /** {@inheritDoc} */
496         public String format( String bundleName, Locale locale, String key, Object arg1, Object arg2 )
497         {
498             return format( bundleName, locale, key, new Object[] { arg1, arg2 } );
499         }
500 
501         /** {@inheritDoc} */
502         public String format( String bundleName, Locale locale, String key, Object[] args )
503         {
504             if ( locale == null )
505             {
506                 locale = getLocale( null );
507             }
508 
509             String value = getString( bundleName, locale, key );
510             if ( args == null )
511             {
512                 args = NO_ARGS;
513             }
514 
515             MessageFormat messageFormat = new MessageFormat( "" );
516             messageFormat.setLocale( locale );
517             messageFormat.applyPattern( value );
518 
519             return messageFormat.format( args );
520         }
521 
522         private String getStringOrNull( ResourceBundle rb, String key )
523         {
524             if ( rb != null )
525             {
526                 try
527                 {
528                     return rb.getString( key );
529                 }
530                 catch ( MissingResourceException ignored )
531                 {
532                     // intentional
533                 }
534             }
535             return null;
536         }
537     }
538 }