1 package org.apache.maven.report.projectinfo;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.OutputStreamWriter;
26 import java.io.Writer;
27 import java.net.MalformedURLException;
28 import java.net.URL;
29 import java.net.URLClassLoader;
30 import java.text.MessageFormat;
31 import java.util.Collection;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Locale;
35 import java.util.Map;
36 import java.util.MissingResourceException;
37 import java.util.ResourceBundle;
38
39 import org.apache.maven.artifact.Artifact;
40 import org.apache.maven.artifact.factory.ArtifactFactory;
41 import org.apache.maven.artifact.repository.ArtifactRepository;
42 import org.apache.maven.artifact.resolver.ArtifactResolver;
43 import org.apache.maven.doxia.site.decoration.Body;
44 import org.apache.maven.doxia.site.decoration.DecorationModel;
45 import org.apache.maven.doxia.siterenderer.Renderer;
46 import org.apache.maven.doxia.siterenderer.RendererException;
47 import org.apache.maven.doxia.siterenderer.RenderingContext;
48 import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
49 import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
50 import org.apache.maven.doxia.tools.SiteTool;
51 import org.apache.maven.doxia.tools.SiteToolException;
52 import org.apache.maven.model.Plugin;
53 import org.apache.maven.plugin.MojoExecutionException;
54 import org.apache.maven.plugins.annotations.Component;
55 import org.apache.maven.plugins.annotations.Parameter;
56 import org.apache.maven.project.MavenProject;
57 import org.apache.maven.project.MavenProjectBuilder;
58 import org.apache.maven.reporting.AbstractMavenReport;
59 import org.apache.maven.reporting.MavenReportException;
60 import org.apache.maven.settings.Settings;
61 import org.codehaus.plexus.i18n.I18N;
62 import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
63 import org.codehaus.plexus.interpolation.InterpolationException;
64 import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
65 import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
66 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
67 import org.codehaus.plexus.util.IOUtil;
68 import org.codehaus.plexus.util.StringUtils;
69 import org.codehaus.plexus.util.xml.Xpp3Dom;
70
71
72
73
74
75
76
77
78 public abstract class AbstractProjectInfoReport
79 extends AbstractMavenReport
80 {
81
82
83
84
85
86
87
88
89
90 @Component
91 protected SiteTool siteTool;
92
93
94
95
96 @Component
97 protected Renderer siteRenderer;
98
99
100
101
102 @Component
103 protected ArtifactResolver resolver;
104
105
106
107
108 @Component
109 protected ArtifactFactory factory;
110
111
112
113
114 @Component
115 private I18N i18n;
116
117
118
119
120 @Component
121 protected MavenProjectBuilder mavenProjectBuilder;
122
123
124
125
126
127
128
129
130
131
132 @Parameter( property = "project.reporting.outputDirectory", required = true )
133 protected File outputDirectory;
134
135
136
137
138 @Parameter( defaultValue = "${project}", readonly = true, required = true )
139 protected MavenProject project;
140
141
142
143
144 @Parameter( property = "localRepository", required = true, readonly = true )
145 protected ArtifactRepository localRepository;
146
147
148
149
150
151
152 @Parameter( property = "project.remoteArtifactRepositories" )
153 protected List<ArtifactRepository> remoteRepositories;
154
155
156
157
158
159
160 @Parameter( defaultValue = "${settings}", readonly = true, required = true )
161 protected Settings settings;
162
163
164
165
166
167
168
169 @Parameter( defaultValue = "${project.basedir}/src/site/custom/project-info-report.properties" )
170 protected String customBundle;
171
172
173
174
175
176
177 @Parameter( property = "mpir.skip", defaultValue = "false" )
178 private boolean skip;
179
180
181
182
183
184
185
186 @Parameter( defaultValue = "true" )
187 protected boolean skipEmptyReport;
188
189
190
191
192
193 @Override
194 public boolean canGenerateReport()
195 {
196 return !skip;
197 }
198
199 @Override
200 public void execute()
201 throws MojoExecutionException
202 {
203 if ( !canGenerateReport() )
204 {
205 return;
206 }
207
208
209 Writer writer = null;
210 try
211 {
212 String filename = getOutputName() + ".html";
213
214 DecorationModel model = new DecorationModel();
215 model.setBody( new Body() );
216
217 Map<String, Object> attributes = new HashMap<String, Object>();
218 attributes.put( "outputEncoding", "UTF-8" );
219 attributes.put( "project", project );
220
221 Locale locale = Locale.getDefault();
222 Artifact defaultSkin =
223 siteTool.getDefaultSkinArtifact( localRepository, project.getRemoteArtifactRepositories() );
224
225
226 SiteRenderingContext siteContext =
227 siteRenderer.createContextForSkin( defaultSkin.getFile(), attributes, model, getName( locale ), locale );
228
229
230 RenderingContext context = new RenderingContext( outputDirectory, filename );
231
232 SiteRendererSink sink = new SiteRendererSink( context );
233
234 generate( sink, null, locale );
235
236 outputDirectory.mkdirs();
237
238 writer = new OutputStreamWriter( new FileOutputStream( new File( outputDirectory, filename ) ), "UTF-8" );
239
240 siteRenderer.generateDocument( writer, sink, siteContext );
241
242 siteRenderer.copyResources( siteContext, new File( project.getBasedir(), "src/site/resources" ),
243 outputDirectory );
244 }
245 catch ( RendererException e )
246 {
247 throw new MojoExecutionException( "An error has occurred in " + getName( Locale.ENGLISH )
248 + " report generation.", e );
249 }
250 catch ( IOException e )
251 {
252 throw new MojoExecutionException( "An error has occurred in " + getName( Locale.ENGLISH )
253 + " report generation.", e );
254 }
255 catch ( SiteToolException e )
256 {
257 throw new MojoExecutionException( "An error has occurred in " + getName( Locale.ENGLISH )
258 + " report generation.", e );
259 }
260 catch ( MavenReportException e )
261 {
262 throw new MojoExecutionException( "An error has occurred in " + getName( Locale.ENGLISH )
263 + " report generation.", e );
264 }
265 finally
266 {
267 IOUtil.close( writer );
268 }
269 }
270
271 @Override
272 public String getCategoryName()
273 {
274 return CATEGORY_PROJECT_INFORMATION;
275 }
276
277
278
279
280
281
282
283
284
285 protected boolean isEmpty( Collection<?> coll )
286 {
287 return coll == null || coll.isEmpty();
288 }
289
290 @Override
291 protected String getOutputDirectory()
292 {
293 return outputDirectory.getAbsolutePath();
294 }
295
296 @Override
297 public File getReportOutputDirectory()
298 {
299 return outputDirectory;
300 }
301
302 @Override
303 public void setReportOutputDirectory( File reportOutputDirectory )
304 {
305 this.outputDirectory = reportOutputDirectory;
306 }
307
308 @Override
309 protected MavenProject getProject()
310 {
311 return project;
312 }
313
314
315
316
317
318 protected Plugin getPlugin( String pluginId )
319 {
320 if ( ( getProject().getBuild() == null ) || ( getProject().getBuild().getPluginsAsMap() == null ) )
321 {
322 return null;
323 }
324
325 Plugin plugin = (Plugin) getProject().getBuild().getPluginsAsMap().get( pluginId );
326
327 if ( ( plugin == null ) && ( getProject().getBuild().getPluginManagement() != null )
328 && ( getProject().getBuild().getPluginManagement().getPluginsAsMap() != null ) )
329 {
330 plugin = (Plugin) getProject().getBuild().getPluginManagement().getPluginsAsMap().get( pluginId );
331 }
332
333 return plugin;
334 }
335
336
337
338
339
340
341 protected String getPluginParameter( String pluginId, String param )
342 {
343 Plugin plugin = getPlugin( pluginId );
344 if ( plugin != null )
345 {
346 Xpp3Dom xpp3Dom = (Xpp3Dom) plugin.getConfiguration();
347 if ( xpp3Dom != null && xpp3Dom.getChild( param ) != null
348 && StringUtils.isNotEmpty( xpp3Dom.getChild( param ).getValue() ) )
349 {
350 return xpp3Dom.getChild( param ).getValue();
351 }
352 }
353
354 return null;
355 }
356
357
358
359
360 @Override
361 protected Renderer getSiteRenderer()
362 {
363 return siteRenderer;
364 }
365
366
367
368
369
370
371 protected String getI18nString( Locale locale, String key )
372 {
373 return getI18N( locale ).getString( "project-info-report", locale, "report." + getI18Nsection() + '.' + key );
374 }
375
376
377
378
379
380 protected I18N getI18N( Locale locale )
381 {
382 if ( customBundle != null )
383 {
384 File customBundleFile = new File( customBundle );
385 if ( customBundleFile.isFile() && customBundleFile.getName().endsWith( ".properties" ) )
386 {
387 if ( !i18n.getClass().isAssignableFrom( CustomI18N.class ) )
388 {
389
390 i18n = new CustomI18N( project, settings, customBundleFile, locale, i18n );
391 }
392 else if ( !i18n.getDefaultLanguage().equals( locale.getLanguage() ) )
393 {
394 i18n = new CustomI18N( project, settings, customBundleFile, locale, i18n );
395 }
396 }
397 }
398
399 return i18n;
400 }
401
402
403
404
405 protected abstract String getI18Nsection();
406
407
408 public String getName( Locale locale )
409 {
410 return getI18nString( locale, "name" );
411 }
412
413
414 public String getDescription( Locale locale )
415 {
416 return getI18nString( locale, "description" );
417 }
418
419 private static class CustomI18N
420 implements I18N
421 {
422 private final MavenProject project;
423
424 private final Settings settings;
425
426 private final String bundleName;
427
428 private final Locale locale;
429
430 private final I18N i18nOriginal;
431
432 private ResourceBundle bundle;
433
434 private static final Object[] NO_ARGS = new Object[0];
435
436 public CustomI18N( MavenProject project, Settings settings, File customBundleFile, Locale locale,
437 I18N i18nOriginal )
438 {
439 super();
440 this.project = project;
441 this.settings = settings;
442 this.locale = locale;
443 this.i18nOriginal = i18nOriginal;
444 this.bundleName =
445 customBundleFile.getName().substring( 0, customBundleFile.getName().indexOf( ".properties" ) );
446
447 URLClassLoader classLoader = null;
448 try
449 {
450 classLoader = new URLClassLoader( new URL[] { customBundleFile.getParentFile().toURI().toURL() } );
451 }
452 catch ( MalformedURLException e )
453 {
454
455 }
456
457 this.bundle = ResourceBundle.getBundle( this.bundleName, locale, classLoader );
458 if ( !this.bundle.getLocale().getLanguage().equals( locale.getLanguage() ) )
459 {
460 this.bundle = ResourceBundle.getBundle( this.bundleName, Locale.getDefault(), classLoader );
461 }
462 }
463
464
465 public String getDefaultLanguage()
466 {
467 return locale.getLanguage();
468 }
469
470
471 public String getDefaultCountry()
472 {
473 return locale.getCountry();
474 }
475
476
477 public String getDefaultBundleName()
478 {
479 return bundleName;
480 }
481
482
483 public String[] getBundleNames()
484 {
485 return new String[] { bundleName };
486 }
487
488
489 public ResourceBundle getBundle()
490 {
491 return bundle;
492 }
493
494
495 public ResourceBundle getBundle( String bundleName )
496 {
497 return bundle;
498 }
499
500
501 public ResourceBundle getBundle( String bundleName, String languageHeader )
502 {
503 return bundle;
504 }
505
506
507 public ResourceBundle getBundle( String bundleName, Locale locale )
508 {
509 return bundle;
510 }
511
512
513 public Locale getLocale( String languageHeader )
514 {
515 return new Locale( languageHeader );
516 }
517
518
519 public String getString( String key )
520 {
521 return getString( bundleName, locale, key );
522 }
523
524
525 public String getString( String key, Locale locale )
526 {
527 return getString( bundleName, locale, key );
528 }
529
530
531 public String getString( String bundleName, Locale locale, String key )
532 {
533 String value;
534
535 if ( locale == null )
536 {
537 locale = getLocale( null );
538 }
539
540 ResourceBundle rb = getBundle( bundleName, locale );
541 value = getStringOrNull( rb, key );
542
543 if ( value == null )
544 {
545
546 value = i18nOriginal.getString( bundleName, locale, key );
547 }
548
549 if ( !value.contains( "${" ) )
550 {
551 return value;
552 }
553
554 final RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
555 try
556 {
557 interpolator.addValueSource( new EnvarBasedValueSource() );
558 }
559 catch ( final IOException e )
560 {
561
562 }
563
564 interpolator.addValueSource( new PropertiesBasedValueSource( System.getProperties() ) );
565 interpolator.addValueSource( new PropertiesBasedValueSource( project.getProperties() ) );
566 interpolator.addValueSource( new PrefixedObjectValueSource( "project", project ) );
567 interpolator.addValueSource( new PrefixedObjectValueSource( "pom", project ) );
568 interpolator.addValueSource( new PrefixedObjectValueSource( "settings", settings ) );
569
570 try
571 {
572 value = interpolator.interpolate( value );
573 }
574 catch ( final InterpolationException e )
575 {
576
577 }
578
579 return value;
580 }
581
582
583 public String format( String key, Object arg1 )
584 {
585 return format( bundleName, locale, key, new Object[] { arg1 } );
586 }
587
588
589 public String format( String key, Object arg1, Object arg2 )
590 {
591 return format( bundleName, locale, key, new Object[] { arg1, arg2 } );
592 }
593
594
595 public String format( String bundleName, Locale locale, String key, Object arg1 )
596 {
597 return format( bundleName, locale, key, new Object[] { arg1 } );
598 }
599
600
601 public String format( String bundleName, Locale locale, String key, Object arg1, Object arg2 )
602 {
603 return format( bundleName, locale, key, new Object[] { arg1, arg2 } );
604 }
605
606
607 public String format( String bundleName, Locale locale, String key, Object[] args )
608 {
609 if ( locale == null )
610 {
611 locale = getLocale( null );
612 }
613
614 String value = getString( bundleName, locale, key );
615 if ( args == null )
616 {
617 args = NO_ARGS;
618 }
619
620 MessageFormat messageFormat = new MessageFormat( "" );
621 messageFormat.setLocale( locale );
622 messageFormat.applyPattern( value );
623
624 return messageFormat.format( args );
625 }
626
627 private String getStringOrNull( ResourceBundle rb, String key )
628 {
629 if ( rb != null )
630 {
631 try
632 {
633 return rb.getString( key );
634 }
635 catch ( MissingResourceException ignored )
636 {
637
638 }
639 }
640 return null;
641 }
642 }
643 }