1 package org.apache.maven.reporting.exec;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.LinkedHashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Map.Entry;
29
30 import org.apache.maven.artifact.repository.DefaultRepositoryRequest;
31 import org.apache.maven.artifact.repository.RepositoryRequest;
32 import org.apache.maven.artifact.resolver.filter.ExclusionSetFilter;
33 import org.apache.maven.execution.MavenSession;
34 import org.apache.maven.lifecycle.LifecycleExecutor;
35 import org.apache.maven.model.Plugin;
36 import org.apache.maven.plugin.MavenPluginManager;
37 import org.apache.maven.plugin.Mojo;
38 import org.apache.maven.plugin.MojoExecution;
39 import org.apache.maven.plugin.MojoExecutionException;
40 import org.apache.maven.plugin.MojoNotFoundException;
41 import org.apache.maven.plugin.PluginConfigurationException;
42 import org.apache.maven.plugin.PluginContainerException;
43 import org.apache.maven.plugin.descriptor.MojoDescriptor;
44 import org.apache.maven.plugin.descriptor.PluginDescriptor;
45 import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
46 import org.apache.maven.plugin.version.PluginVersionRequest;
47 import org.apache.maven.plugin.version.PluginVersionResolutionException;
48 import org.apache.maven.plugin.version.PluginVersionResolver;
49 import org.apache.maven.plugin.version.PluginVersionResult;
50 import org.apache.maven.project.MavenProject;
51 import org.apache.maven.reporting.MavenReport;
52 import org.codehaus.classworlds.ClassRealm;
53 import org.codehaus.plexus.component.annotations.Component;
54 import org.codehaus.plexus.component.annotations.Requirement;
55 import org.codehaus.plexus.configuration.PlexusConfiguration;
56 import org.codehaus.plexus.logging.Logger;
57 import org.codehaus.plexus.util.StringUtils;
58 import org.codehaus.plexus.util.xml.Xpp3Dom;
59 import org.codehaus.plexus.util.xml.Xpp3DomUtils;
60 import org.sonatype.aether.repository.RemoteRepository;
61 import org.sonatype.aether.util.filter.ExclusionsDependencyFilter;
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102 @Component( role = MavenReportExecutor.class )
103 public class DefaultMavenReportExecutor
104 implements MavenReportExecutor
105 {
106 @Requirement
107 private Logger logger;
108
109 @Requirement
110 protected MavenPluginManager mavenPluginManager;
111
112 @Requirement
113 protected LifecycleExecutor lifecycleExecutor;
114
115 @Requirement
116 protected PluginVersionResolver pluginVersionResolver;
117
118 private static final List<String> IMPORTS = Arrays.asList( "org.apache.maven.reporting.MavenReport",
119 "org.apache.maven.reporting.MavenMultiPageReport",
120 "org.apache.maven.doxia.siterenderer.Renderer",
121 "org.apache.maven.doxia.sink.SinkFactory",
122 "org.codehaus.doxia.sink.Sink",
123 "org.apache.maven.doxia.sink.Sink",
124 "org.apache.maven.doxia.sink.SinkEventAttributes",
125 "org.apache.maven.doxia.logging.LogEnabled",
126 "org.apache.maven.doxia.logging.Log" );
127
128 private static final ExclusionsDependencyFilter EXCLUDES =
129 new ExclusionsDependencyFilter( Arrays.asList( "doxia-site-renderer", "doxia-sink-api", "maven-reporting-api" ) );
130
131 public List<MavenReportExecution> buildMavenReports( MavenReportExecutorRequest mavenReportExecutorRequest )
132 throws MojoExecutionException
133 {
134 if ( mavenReportExecutorRequest.getReportPlugins() == null )
135 {
136 return Collections.emptyList();
137 }
138 getLog().debug( "DefaultMavenReportExecutor.buildMavenReports()" );
139
140 List<String> reportPluginKeys = new ArrayList<String>();
141 List<MavenReportExecution> reports = new ArrayList<MavenReportExecution>();
142
143 String pluginKey = "";
144 try
145 {
146 for ( ReportPlugin reportPlugin : mavenReportExecutorRequest.getReportPlugins() )
147 {
148 pluginKey = reportPlugin.getGroupId() + ":" + reportPlugin.getArtifactId();
149
150 buildReportPlugin( mavenReportExecutorRequest, reportPlugin, reportPluginKeys, reports );
151 }
152 return reports;
153 }
154 catch ( Exception e )
155 {
156 throw new MojoExecutionException( "failed to get report for " + pluginKey, e );
157 }
158 }
159
160 protected void buildReportPlugin( MavenReportExecutorRequest mavenReportExecutorRequest, ReportPlugin reportPlugin,
161 List<String> reportPluginKeys, List<MavenReportExecution> reports )
162 throws Exception
163 {
164 Plugin plugin = new Plugin();
165 plugin.setGroupId( reportPlugin.getGroupId() );
166 plugin.setArtifactId( reportPlugin.getArtifactId() );
167
168 String pluginKey = reportPlugin.getGroupId() + ":" + reportPlugin.getArtifactId();
169 if ( reportPluginKeys.contains( pluginKey ) )
170 {
171 logger.info( "plugin " + pluginKey + " will be executed more than one time" );
172 }
173 else
174 {
175 reportPluginKeys.add( pluginKey );
176 }
177
178 RepositoryRequest repositoryRequest = new DefaultRepositoryRequest();
179 repositoryRequest.setLocalRepository( mavenReportExecutorRequest.getLocalRepository() );
180 repositoryRequest.setRemoteRepositories( mavenReportExecutorRequest.getProject().getPluginArtifactRepositories() );
181
182 plugin.setVersion( getPluginVersion( reportPlugin, repositoryRequest, mavenReportExecutorRequest ) );
183
184 mergePluginToReportPlugin( mavenReportExecutorRequest, plugin, reportPlugin );
185
186 logger.info( "configuring report plugin " + plugin.getId() );
187
188 MavenSession session = mavenReportExecutorRequest.getMavenSession();
189 List<RemoteRepository> remoteRepositories = session.getCurrentProject().getRemotePluginRepositories();
190
191 PluginDescriptor pluginDescriptor =
192 mavenPluginManager.getPluginDescriptor( plugin, remoteRepositories, session.getRepositorySession() );
193
194 Map<String, PlexusConfiguration> goalsWithConfiguration = new LinkedHashMap<String, PlexusConfiguration>();
195
196 if ( reportPlugin.getReportSets().isEmpty() && reportPlugin.getReports().isEmpty() )
197 {
198 List<MojoDescriptor> mojoDescriptors = pluginDescriptor.getMojos();
199 for ( MojoDescriptor mojoDescriptor : mojoDescriptors )
200 {
201 goalsWithConfiguration.put( mojoDescriptor.getGoal(), mojoDescriptor.getConfiguration() );
202 }
203 }
204 else
205 {
206 for ( ReportSet reportSet : reportPlugin.getReportSets() )
207 {
208 for ( String report : reportSet.getReports() )
209 {
210 goalsWithConfiguration.put( report, reportSet.getConfiguration() );
211 }
212 }
213
214 for ( String report : reportPlugin.getReports() )
215 {
216 goalsWithConfiguration.put( report, reportPlugin.getConfiguration() );
217 }
218 }
219
220 for ( Entry<String, PlexusConfiguration> entry : goalsWithConfiguration.entrySet() )
221 {
222 MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( entry.getKey() );
223 if ( mojoDescriptor == null )
224 {
225 throw new MojoNotFoundException( entry.getKey(), pluginDescriptor );
226 }
227
228 MojoExecution mojoExecution = new MojoExecution( plugin, entry.getKey(), "report:" + entry.getKey() );
229
230 mojoExecution.setConfiguration( convert( mojoDescriptor ) );
231
232 if ( reportPlugin.getConfiguration() != null || entry.getValue() != null )
233 {
234 Xpp3Dom reportConfiguration =
235 reportPlugin.getConfiguration() == null ? new Xpp3Dom( "fake" )
236 : convert( reportPlugin.getConfiguration() );
237
238
239 Xpp3Dom mergedConfigurationWithReportSet =
240 Xpp3DomUtils.mergeXpp3Dom( convert( entry.getValue() ), reportConfiguration );
241
242 Xpp3Dom mergedConfiguration =
243 Xpp3DomUtils.mergeXpp3Dom( mergedConfigurationWithReportSet, convert( mojoDescriptor ) );
244
245 Xpp3Dom cleanedConfiguration = new Xpp3Dom( "configuration" );
246 if ( mergedConfiguration.getChildren() != null )
247 {
248 for ( Xpp3Dom parameter : mergedConfiguration.getChildren() )
249 {
250 if ( mojoDescriptor.getParameterMap().containsKey( parameter.getName() ) )
251 {
252 cleanedConfiguration.addChild( parameter );
253 }
254 }
255 }
256 if ( getLog().isDebugEnabled() )
257 {
258 getLog().debug( "mojoExecution mergedConfiguration: " + mergedConfiguration );
259 getLog().debug( "mojoExecution cleanedConfiguration: " + cleanedConfiguration );
260 }
261
262 mojoExecution.setConfiguration( cleanedConfiguration );
263 }
264
265 mojoExecution.setMojoDescriptor( mojoDescriptor );
266
267 mavenPluginManager.setupPluginRealm( pluginDescriptor, mavenReportExecutorRequest.getMavenSession(),
268 Thread.currentThread().getContextClassLoader(), IMPORTS, EXCLUDES );
269 MavenReport mavenReport =
270 getConfiguredMavenReport( mojoExecution, pluginDescriptor, mavenReportExecutorRequest );
271
272 if ( mavenReport == null )
273 {
274 continue;
275 }
276
277 MavenReportExecution mavenReportExecution =
278 new MavenReportExecution( mojoExecution.getPlugin(), mavenReport, pluginDescriptor.getClassRealm() );
279
280 lifecycleExecutor.calculateForkedExecutions( mojoExecution, mavenReportExecutorRequest.getMavenSession() );
281
282 if ( !mojoExecution.getForkedExecutions().isEmpty() )
283 {
284 lifecycleExecutor.executeForkedExecutions( mojoExecution, mavenReportExecutorRequest.getMavenSession() );
285 }
286
287 if ( canGenerateReport( mavenReport, mojoExecution ) )
288 {
289 reports.add( mavenReportExecution );
290 }
291 }
292 }
293
294 private boolean canGenerateReport( MavenReport mavenReport, MojoExecution mojoExecution )
295 {
296 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
297 try
298 {
299 Thread.currentThread().setContextClassLoader( mojoExecution.getMojoDescriptor().getRealm() );
300
301 return mavenReport.canGenerateReport();
302 }
303 finally
304 {
305 Thread.currentThread().setContextClassLoader( originalClassLoader );
306 }
307 }
308
309 private MavenReport getConfiguredMavenReport( MojoExecution mojoExecution, PluginDescriptor pluginDescriptor,
310 MavenReportExecutorRequest mavenReportExecutorRequest )
311 throws PluginContainerException, PluginConfigurationException
312 {
313 try
314 {
315 if ( !isMavenReport( mojoExecution, pluginDescriptor ) )
316 {
317 return null;
318 }
319
320 Mojo mojo = mavenPluginManager.getConfiguredMojo( Mojo.class,
321 mavenReportExecutorRequest.getMavenSession(),
322 mojoExecution );
323
324 return (MavenReport) mojo;
325 }
326 catch ( ClassCastException e )
327 {
328 getLog().warn( "skip ClassCastException " + e.getMessage() );
329 return null;
330 }
331 catch ( PluginContainerException e )
332 {
333
334
335
336
337 if ( e.getCause() != null && e.getCause() instanceof NoClassDefFoundError
338 && e.getMessage().contains( "PluginRegistry" ) )
339 {
340 getLog().warn( "skip NoClassDefFoundError with PluginRegistry " );
341
342 if ( getLog().isDebugEnabled() )
343 {
344 getLog().debug( e.getMessage(), e );
345 }
346 return null;
347 }
348 throw e;
349 }
350 }
351
352 private boolean isMavenReport( MojoExecution mojoExecution, PluginDescriptor pluginDescriptor )
353 {
354 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
355 Class<?> mojoClass;
356 Thread.currentThread().setContextClassLoader( mojoExecution.getMojoDescriptor().getRealm() );
357 try
358 {
359 mojoClass =
360 pluginDescriptor.getClassRealm().loadClass( mojoExecution.getMojoDescriptor().getImplementation() );
361 }
362 catch ( ClassNotFoundException e )
363 {
364 getLog().warn( "skip ClassNotFoundException mojoExecution.goal '" + mojoExecution.getGoal() + "': "
365 + e.getMessage(), e );
366 return false;
367 }
368 finally
369 {
370 Thread.currentThread().setContextClassLoader( originalClassLoader );
371 }
372
373 try
374 {
375 Thread.currentThread().setContextClassLoader( mojoExecution.getMojoDescriptor().getRealm() );
376 MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( mojoExecution.getGoal() );
377
378 boolean isMavenReport = MavenReport.class.isAssignableFrom( mojoClass );
379
380 if ( getLog().isDebugEnabled() )
381 {
382 if ( mojoDescriptor != null && mojoDescriptor.getImplementationClass() != null )
383 {
384 getLog().debug( "class " + mojoDescriptor.getImplementationClass().getName() + " isMavenReport: "
385 + isMavenReport );
386 }
387
388 if ( !isMavenReport )
389 {
390 getLog().debug( "skip non MavenReport " + mojoExecution.getMojoDescriptor().getId() );
391 }
392 }
393
394 return isMavenReport;
395 }
396 catch ( LinkageError e )
397 {
398 getLog().warn( "skip LinkageError mojoExecution.goal '" + mojoExecution.getGoal() + "': " + e.getMessage(),
399 e );
400 return false;
401 }
402 finally
403 {
404 Thread.currentThread().setContextClassLoader( originalClassLoader );
405 }
406 }
407
408 private Xpp3Dom convert( MojoDescriptor mojoDescriptor )
409 {
410 PlexusConfiguration config = mojoDescriptor.getMojoConfiguration();
411 return ( config != null ) ? convert( config ) : new Xpp3Dom( "configuration" );
412 }
413
414 private Xpp3Dom convert( PlexusConfiguration config )
415 {
416 if ( config == null )
417 {
418 return null;
419 }
420
421 Xpp3Dom dom = new Xpp3Dom( config.getName() );
422 dom.setValue( config.getValue( null ) );
423
424 for ( String attrib : config.getAttributeNames() )
425 {
426 dom.setAttribute( attrib, config.getAttribute( attrib, null ) );
427 }
428
429 for ( int n = config.getChildCount(), i = 0; i < n; i++ )
430 {
431 dom.addChild( convert( config.getChild( i ) ) );
432 }
433
434 return dom;
435 }
436
437 private Logger getLog()
438 {
439 return logger;
440 }
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458 protected String getPluginVersion( ReportPlugin reportPlugin, RepositoryRequest repositoryRequest,
459 MavenReportExecutorRequest mavenReportExecutorRequest )
460 throws PluginVersionResolutionException
461 {
462 String reportPluginKey = reportPlugin.getGroupId() + ':' + reportPlugin.getArtifactId();
463 if ( getLog().isDebugEnabled() )
464 {
465 getLog().debug( "resolving version for " + reportPluginKey );
466 }
467
468
469 if ( reportPlugin.getVersion() != null )
470 {
471 if ( getLog().isDebugEnabled() )
472 {
473 logger.debug( "resolved " + reportPluginKey + " version from the reporting.plugins section: "
474 + reportPlugin.getVersion() );
475 }
476 return reportPlugin.getVersion();
477 }
478
479 MavenProject project = mavenReportExecutorRequest.getProject();
480
481
482 if ( project.getBuild() != null )
483 {
484 Plugin plugin = find( reportPlugin, project.getBuild().getPlugins() );
485
486 if ( plugin != null && plugin.getVersion() != null )
487 {
488 if ( getLog().isDebugEnabled() )
489 {
490 logger.debug( "resolved " + reportPluginKey + " version from the build.plugins section: "
491 + plugin.getVersion() );
492 }
493 return plugin.getVersion();
494 }
495 }
496
497
498 if ( project.getBuild() != null && project.getBuild().getPluginManagement() != null )
499 {
500 Plugin plugin = find( reportPlugin, project.getBuild().getPluginManagement().getPlugins() );
501
502 if ( plugin != null && plugin.getVersion() != null )
503 {
504 if ( getLog().isDebugEnabled() )
505 {
506 logger.debug( "resolved " + reportPluginKey
507 + " version from the build.pluginManagement.plugins section: " + plugin.getVersion() );
508 }
509 return plugin.getVersion();
510 }
511 }
512
513
514 logger.warn( "Report plugin " + reportPluginKey + " has an empty version." );
515 logger.warn( "" );
516 logger.warn( "It is highly recommended to fix these problems"
517 + " because they threaten the stability of your build." );
518 logger.warn( "" );
519 logger.warn( "For this reason, future Maven versions might no"
520 + " longer support building such malformed projects." );
521
522 Plugin plugin = new Plugin();
523 plugin.setGroupId( reportPlugin.getGroupId() );
524 plugin.setArtifactId( reportPlugin.getArtifactId() );
525
526 PluginVersionRequest pluginVersionRequest =
527 new DefaultPluginVersionRequest( plugin, mavenReportExecutorRequest.getMavenSession() );
528
529 PluginVersionResult result = pluginVersionResolver.resolve( pluginVersionRequest );
530 if ( getLog().isDebugEnabled() )
531 {
532 getLog().debug( "resolved " + reportPluginKey + " version from repository: " + result.getVersion() );
533 }
534 return result.getVersion();
535 }
536
537
538
539
540
541
542
543
544 private Plugin find( ReportPlugin reportPlugin, List<Plugin> plugins )
545 {
546 if ( plugins == null )
547 {
548 return null;
549 }
550 for ( Plugin plugin : plugins )
551 {
552 if ( StringUtils.equals( plugin.getArtifactId(), reportPlugin.getArtifactId() )
553 && StringUtils.equals( plugin.getGroupId(), reportPlugin.getGroupId() ) )
554 {
555 return plugin;
556 }
557 }
558 return null;
559 }
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574 private void mergePluginToReportPlugin( MavenReportExecutorRequest mavenReportExecutorRequest, Plugin buildPlugin,
575 ReportPlugin reportPlugin )
576 {
577 Plugin configuredPlugin = find( reportPlugin, mavenReportExecutorRequest.getProject().getBuild().getPlugins() );
578 if ( configuredPlugin != null )
579 {
580 if ( !configuredPlugin.getDependencies().isEmpty() )
581 {
582 buildPlugin.getDependencies().addAll( configuredPlugin.getDependencies() );
583 }
584 }
585 }
586 }