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