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