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