1
2 package org.apache.maven.plugin;
3
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 */
22
23 import java.io.File;
24 import java.net.URL;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.Iterator;
31 import java.util.LinkedHashMap;
32 import java.util.LinkedHashSet;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Set;
36
37 import org.apache.maven.MavenArtifactFilterManager;
38 import org.apache.maven.artifact.Artifact;
39 import org.apache.maven.artifact.factory.ArtifactFactory;
40 import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
41 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
42 import org.apache.maven.artifact.metadata.ResolutionGroup;
43 import org.apache.maven.artifact.repository.ArtifactRepository;
44 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
45 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
46 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
47 import org.apache.maven.artifact.resolver.ArtifactResolver;
48 import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
49 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
50 import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
51 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
52 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
53 import org.apache.maven.artifact.versioning.VersionRange;
54 import org.apache.maven.execution.MavenSession;
55 import org.apache.maven.execution.RuntimeInformation;
56 import org.apache.maven.model.Plugin;
57 import org.apache.maven.model.ReportPlugin;
58 import org.apache.maven.monitor.event.EventDispatcher;
59 import org.apache.maven.monitor.event.MavenEvents;
60 import org.apache.maven.monitor.logging.DefaultLog;
61 import org.apache.maven.plugin.descriptor.MojoDescriptor;
62 import org.apache.maven.plugin.descriptor.Parameter;
63 import org.apache.maven.plugin.descriptor.PluginDescriptor;
64 import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
65 import org.apache.maven.plugin.logging.Log;
66 import org.apache.maven.plugin.version.PluginVersionManager;
67 import org.apache.maven.plugin.version.PluginVersionNotFoundException;
68 import org.apache.maven.plugin.version.PluginVersionResolutionException;
69 import org.apache.maven.project.MavenProject;
70 import org.apache.maven.project.MavenProjectBuilder;
71 import org.apache.maven.project.ProjectBuildingException;
72 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
73 import org.apache.maven.project.artifact.MavenMetadataSource;
74 import org.apache.maven.project.path.PathTranslator;
75 import org.apache.maven.reporting.MavenReport;
76 import org.apache.maven.settings.Settings;
77 import org.codehaus.classworlds.ClassRealm;
78 import org.codehaus.classworlds.NoSuchRealmException;
79 import org.codehaus.plexus.PlexusConstants;
80 import org.codehaus.plexus.PlexusContainer;
81 import org.codehaus.plexus.PlexusContainerException;
82 import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
83 import org.codehaus.plexus.component.configurator.ComponentConfigurator;
84 import org.codehaus.plexus.component.configurator.ConfigurationListener;
85 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
86 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
87 import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
88 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
89 import org.codehaus.plexus.configuration.PlexusConfiguration;
90 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
91 import org.codehaus.plexus.context.Context;
92 import org.codehaus.plexus.context.ContextException;
93 import org.codehaus.plexus.logging.AbstractLogEnabled;
94 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
95 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
96 import org.codehaus.plexus.util.StringUtils;
97 import org.codehaus.plexus.util.xml.Xpp3Dom;
98
99 public class DefaultPluginManager
100 extends AbstractLogEnabled
101 implements PluginManager, Initializable, Contextualizable
102 {
103 protected PlexusContainer container;
104
105 protected PluginDescriptorBuilder pluginDescriptorBuilder;
106
107 protected ArtifactFilter artifactFilter;
108
109 private Log mojoLogger;
110
111 private Map resolvedCoreArtifactFiles = new HashMap();
112
113 // component requirements
114 protected PathTranslator pathTranslator;
115
116 protected MavenPluginCollector pluginCollector;
117
118 protected PluginVersionManager pluginVersionManager;
119
120 protected ArtifactFactory artifactFactory;
121
122 protected ArtifactResolver artifactResolver;
123
124 protected ArtifactMetadataSource artifactMetadataSource;
125
126 protected RuntimeInformation runtimeInformation;
127
128 protected MavenProjectBuilder mavenProjectBuilder;
129
130 protected PluginMappingManager pluginMappingManager;
131
132 // END component requirements
133
134 public DefaultPluginManager()
135 {
136 pluginDescriptorBuilder = new PluginDescriptorBuilder();
137 }
138
139 // ----------------------------------------------------------------------
140 //
141 // ----------------------------------------------------------------------
142
143 public PluginDescriptor getPluginDescriptorForPrefix( String prefix )
144 {
145 return pluginCollector.getPluginDescriptorForPrefix( prefix );
146 }
147
148 public Plugin getPluginDefinitionForPrefix( String prefix,
149 MavenSession session,
150 MavenProject project )
151 {
152 // TODO: since this is only used in the lifecycle executor, maybe it should be moved there? There is no other
153 // use for the mapping manager in here
154 return pluginMappingManager.getByPrefix( prefix, session.getSettings().getPluginGroups(),
155 project.getPluginArtifactRepositories(),
156 session.getLocalRepository() );
157 }
158
159 public PluginDescriptor verifyPlugin( Plugin plugin,
160 MavenProject project,
161 Settings settings,
162 ArtifactRepository localRepository )
163 throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
164 InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
165 PluginVersionNotFoundException
166 {
167 // TODO: this should be possibly outside
168 // All version-resolution logic has been moved to DefaultPluginVersionManager.
169 if ( plugin.getVersion() == null )
170 {
171 String version = pluginVersionManager.resolvePluginVersion( plugin.getGroupId(), plugin.getArtifactId(),
172 project, settings, localRepository );
173 plugin.setVersion( version );
174 }
175
176 return verifyVersionedPlugin( plugin, project, localRepository );
177 }
178
179 private PluginDescriptor verifyVersionedPlugin( Plugin plugin,
180 MavenProject project,
181 ArtifactRepository localRepository )
182 throws PluginVersionResolutionException, ArtifactNotFoundException, ArtifactResolutionException,
183 InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException
184 {
185 // TODO: this might result in an artifact "RELEASE" being resolved continuously
186 // FIXME: need to find out how a plugin gets marked as 'installed'
187 // and no ChildContainer exists. The check for that below fixes
188 // the 'Can't find plexus container for plugin: xxx' error.
189 try
190 {
191 VersionRange versionRange = VersionRange.createFromVersionSpec( plugin.getVersion() );
192
193 List remoteRepositories = new ArrayList();
194 remoteRepositories.addAll( project.getPluginArtifactRepositories() );
195 remoteRepositories.addAll( project.getRemoteArtifactRepositories() );
196
197 checkRequiredMavenVersion( plugin, localRepository, remoteRepositories );
198
199 Artifact pluginArtifact =
200 artifactFactory.createPluginArtifact( plugin.getGroupId(), plugin.getArtifactId(), versionRange );
201
202 pluginArtifact = project.replaceWithActiveArtifact( pluginArtifact );
203
204 artifactResolver.resolve( pluginArtifact, project.getPluginArtifactRepositories(), localRepository );
205
206 PlexusContainer pluginContainer = container.getChildContainer( plugin.getKey() );
207
208 File pluginFile = pluginArtifact.getFile();
209
210 if ( !pluginCollector.isPluginInstalled( plugin ) || ( pluginContainer == null ) )
211 {
212 addPlugin( plugin, pluginArtifact, project, localRepository );
213 }
214 else if ( pluginFile.lastModified() > pluginContainer.getCreationDate().getTime() )
215 {
216 getLogger().info(
217 "Reloading plugin container for: " + plugin.getKey() + ". The plugin artifact has changed." );
218
219 pluginContainer.dispose();
220
221 pluginCollector.flushPluginDescriptor( plugin );
222
223 addPlugin( plugin, pluginArtifact, project, localRepository );
224 }
225
226 project.addPlugin( plugin );
227 }
228 catch ( ArtifactNotFoundException e )
229 {
230 String groupId = plugin.getGroupId();
231 String artifactId = plugin.getArtifactId();
232 String version = plugin.getVersion();
233
234 if ( ( groupId == null ) || ( artifactId == null ) || ( version == null ) )
235 {
236 throw new PluginNotFoundException( e );
237 }
238 else if ( groupId.equals( e.getGroupId() ) && artifactId.equals( e.getArtifactId() ) &&
239 version.equals( e.getVersion() ) && "maven-plugin".equals( e.getType() ) )
240 {
241 throw new PluginNotFoundException( e );
242 }
243 else
244 {
245 throw e;
246 }
247 }
248
249 return pluginCollector.getPluginDescriptor( plugin );
250 }
251
252 /**
253 * @todo would be better to store this in the plugin descriptor, but then it won't be available to the version
254 * manager which executes before the plugin is instantiated
255 */
256 private void checkRequiredMavenVersion( Plugin plugin,
257 ArtifactRepository localRepository,
258 List remoteRepositories )
259 throws PluginVersionResolutionException, InvalidPluginException
260 {
261 try
262 {
263 Artifact artifact = artifactFactory.createProjectArtifact( plugin.getGroupId(), plugin.getArtifactId(),
264 plugin.getVersion() );
265 MavenProject project =
266 mavenProjectBuilder.buildFromRepository( artifact, remoteRepositories, localRepository, false );
267 // if we don't have the required Maven version, then ignore an update
268 if ( ( project.getPrerequisites() != null ) && ( project.getPrerequisites().getMaven() != null ) )
269 {
270 DefaultArtifactVersion requiredVersion =
271 new DefaultArtifactVersion( project.getPrerequisites().getMaven() );
272 if ( runtimeInformation.getApplicationVersion().compareTo( requiredVersion ) < 0 )
273 {
274 throw new PluginVersionResolutionException( plugin.getGroupId(), plugin.getArtifactId(),
275 "Plugin requires Maven version " + requiredVersion );
276 }
277 }
278 }
279 catch ( ProjectBuildingException e )
280 {
281 throw new InvalidPluginException(
282 "Unable to build project for plugin '" + plugin.getKey() + "': " + e.getMessage(), e );
283 }
284 }
285
286 protected void addPlugin( Plugin plugin,
287 Artifact pluginArtifact,
288 MavenProject project,
289 ArtifactRepository localRepository )
290 throws PluginManagerException, InvalidPluginException
291 {
292 PlexusContainer child;
293
294 try
295 {
296 child = container.createChildContainer( plugin.getKey(),
297 Collections.singletonList( pluginArtifact.getFile() ),
298 Collections.EMPTY_MAP,
299 Collections.singletonList( pluginCollector ) );
300 try
301 {
302 child.getContainerRealm().importFrom( "plexus.core", "org.codehaus.plexus.util.xml.Xpp3Dom" );
303 child.getContainerRealm().importFrom( "plexus.core", "org.codehaus.plexus.util.xml.pull" );
304
305 // MNG-2878
306 child.getContainerRealm().importFrom( "plexus.core", "/default-report.xml" );
307 }
308 catch ( NoSuchRealmException e )
309 {
310 // won't happen
311 }
312 }
313 catch ( PlexusContainerException e )
314 {
315 throw new PluginManagerException(
316 "Failed to create plugin container for plugin '" + plugin + "': " + e.getMessage(), e );
317 }
318
319 // this plugin's descriptor should have been discovered in the child creation, so we should be able to
320 // circle around and set the artifacts and class realm
321 PluginDescriptor addedPlugin = pluginCollector.getPluginDescriptor( plugin );
322
323 if ( addedPlugin == null )
324 {
325 throw new IllegalStateException( "The PluginDescriptor for the plugin " + plugin + " was not found." );
326 }
327
328 addedPlugin.setClassRealm( child.getContainerRealm() );
329
330 // we're only setting the plugin's artifact itself as the artifact list, to allow it to be retrieved
331 // later when the plugin is first invoked. Retrieving this artifact will in turn allow us to
332 // transitively resolve its dependencies, and add them to the plugin container...
333 addedPlugin.setArtifacts( Collections.singletonList( pluginArtifact ) );
334
335 try
336 {
337 // the only Plugin instance which will have dependencies is the one specified in the project.
338 // We need to look for a Plugin instance there, in case the instance we're using didn't come from
339 // the project.
340 Plugin projectPlugin = (Plugin) project.getBuild().getPluginsAsMap().get( plugin.getKey() );
341
342 if ( projectPlugin == null )
343 {
344 projectPlugin = plugin;
345 }
346
347 Set artifacts = MavenMetadataSource.createArtifacts( artifactFactory, projectPlugin.getDependencies(), null,
348 null, project );
349
350 // Set artifacts =
351 // MavenMetadataSource.createArtifacts( artifactFactory, plugin.getDependencies(), null, null, project );
352
353 addedPlugin.setIntroducedDependencyArtifacts( artifacts );
354 }
355 catch ( InvalidDependencyVersionException e )
356 {
357 throw new InvalidPluginException( "Plugin '" + plugin + "' is invalid: " + e.getMessage(), e );
358 }
359 }
360
361 // ----------------------------------------------------------------------
362 // Mojo execution
363 // ----------------------------------------------------------------------
364
365 public void executeMojo( MavenProject project,
366 MojoExecution mojoExecution,
367 MavenSession session )
368 throws ArtifactResolutionException, MojoExecutionException, MojoFailureException, ArtifactNotFoundException,
369 InvalidDependencyVersionException, PluginManagerException, PluginConfigurationException
370 {
371 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
372
373 // NOTE: I'm putting these checks in here, since this is the central point of access for
374 // anything that wants to execute a mojo.
375 if ( mojoDescriptor.isProjectRequired() && !session.isUsingPOMsFromFilesystem() )
376 {
377 throw new MojoExecutionException( "Cannot execute mojo: " + mojoDescriptor.getGoal() +
378 ". It requires a project with an existing pom.xml, but the build is not using one." );
379 }
380
381 if ( mojoDescriptor.isOnlineRequired() && session.getSettings().isOffline() )
382 {
383 // TODO: Should we error out, or simply warn and skip??
384 throw new MojoExecutionException( "Mojo: " + mojoDescriptor.getGoal() +
385 " requires online mode for execution. Maven is currently offline." );
386 }
387
388 if ( mojoDescriptor.isDependencyResolutionRequired() != null )
389 {
390 Collection projects;
391
392 if ( mojoDescriptor.isAggregator() )
393 {
394 projects = session.getSortedProjects();
395 }
396 else
397 {
398 projects = Collections.singleton( project );
399 }
400
401 for ( Iterator i = projects.iterator(); i.hasNext(); )
402 {
403 MavenProject p = (MavenProject) i.next();
404
405 resolveTransitiveDependencies( session, artifactResolver,
406 mojoDescriptor.isDependencyResolutionRequired(), artifactFactory, p, mojoDescriptor.isAggregator() );
407 }
408
409 downloadDependencies( project, session, artifactResolver );
410 }
411
412 String goalName = mojoDescriptor.getFullGoalName();
413
414 Mojo plugin;
415
416 PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
417 String goalId = mojoDescriptor.getGoal();
418 String groupId = pluginDescriptor.getGroupId();
419 String artifactId = pluginDescriptor.getArtifactId();
420 String executionId = mojoExecution.getExecutionId();
421 Xpp3Dom dom = project.getGoalConfiguration( groupId, artifactId, executionId, goalId );
422 Xpp3Dom reportDom = project.getReportConfiguration( groupId, artifactId, executionId );
423 dom = Xpp3Dom.mergeXpp3Dom( dom, reportDom );
424 if ( mojoExecution.getConfiguration() != null )
425 {
426 dom = Xpp3Dom.mergeXpp3Dom( dom, mojoExecution.getConfiguration() );
427 }
428
429 plugin = getConfiguredMojo( session, dom, project, false, mojoExecution );
430
431 // Event monitoring.
432 String event = MavenEvents.MOJO_EXECUTION;
433 EventDispatcher dispatcher = session.getEventDispatcher();
434
435 String goalExecId = goalName;
436
437 if ( mojoExecution.getExecutionId() != null )
438 {
439 goalExecId += " {execution: " + mojoExecution.getExecutionId() + "}";
440 }
441
442 dispatcher.dispatchStart( event, goalExecId );
443
444 ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
445
446 try
447 {
448 Thread.currentThread().setContextClassLoader(
449 mojoDescriptor.getPluginDescriptor().getClassRealm().getClassLoader() );
450
451 plugin.execute();
452
453 dispatcher.dispatchEnd( event, goalExecId );
454 }
455 catch ( MojoExecutionException e )
456 {
457 session.getEventDispatcher().dispatchError( event, goalExecId, e );
458
459 throw e;
460 }
461 catch ( MojoFailureException e )
462 {
463 session.getEventDispatcher().dispatchError( event, goalExecId, e );
464
465 throw e;
466 }
467 catch ( LinkageError e )
468 {
469 if ( getLogger().isFatalErrorEnabled() )
470 {
471 getLogger().fatalError(
472 plugin.getClass().getName() + "#execute() caused a linkage error ("
473 + e.getClass().getName() + ") and may be out-of-date. Check the realms:" );
474
475 ClassRealm pluginRealm = mojoDescriptor.getPluginDescriptor().getClassRealm();
476 StringBuffer sb = new StringBuffer();
477 sb.append( "Plugin realm = " + pluginRealm.getId() ).append( '\n' );
478 for ( int i = 0; i < pluginRealm.getConstituents().length; i++ )
479 {
480 sb.append( "urls[" + i + "] = " + pluginRealm.getConstituents()[i] );
481 if ( i != ( pluginRealm.getConstituents().length - 1 ) )
482 {
483 sb.append( '\n' );
484 }
485 }
486 getLogger().fatalError( sb.toString() );
487
488 ClassRealm containerRealm = container.getContainerRealm();
489 sb = new StringBuffer();
490 sb.append( "Container realm = " + containerRealm.getId() ).append( '\n' );
491 for ( int i = 0; i < containerRealm.getConstituents().length; i++ )
492 {
493 sb.append( "urls[" + i + "] = " + containerRealm.getConstituents()[i] );
494 if ( i != ( containerRealm.getConstituents().length - 1 ) )
495 {
496 sb.append( '\n' );
497 }
498 }
499 getLogger().fatalError( sb.toString() );
500 }
501
502 session.getEventDispatcher().dispatchError( event, goalExecId, e );
503
504 throw e;
505 }
506 finally
507 {
508
509 Thread.currentThread().setContextClassLoader( oldClassLoader );
510
511 try
512 {
513 PlexusContainer pluginContainer = getPluginContainer( mojoDescriptor.getPluginDescriptor() );
514
515 pluginContainer.release( plugin );
516 }
517 catch ( ComponentLifecycleException e )
518 {
519 if ( getLogger().isErrorEnabled() )
520 {
521 getLogger().error( "Error releasing plugin - ignoring.", e );
522 }
523 }
524 }
525 }
526
527 public MavenReport getReport( MavenProject project,
528 MojoExecution mojoExecution,
529 MavenSession session )
530 throws ArtifactNotFoundException, PluginConfigurationException, PluginManagerException,
531 ArtifactResolutionException
532 {
533 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
534 PluginDescriptor descriptor = mojoDescriptor.getPluginDescriptor();
535 Xpp3Dom dom = project.getReportConfiguration( descriptor.getGroupId(), descriptor.getArtifactId(),
536 mojoExecution.getExecutionId() );
537 if ( mojoExecution.getConfiguration() != null )
538 {
539 dom = Xpp3Dom.mergeXpp3Dom( dom, mojoExecution.getConfiguration() );
540 }
541
542 return (MavenReport) getConfiguredMojo( session, dom, project, true, mojoExecution );
543 }
544
545 public PluginDescriptor verifyReportPlugin( ReportPlugin reportPlugin,
546 MavenProject project,
547 MavenSession session )
548 throws PluginVersionResolutionException, ArtifactResolutionException, ArtifactNotFoundException,
549 InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
550 PluginVersionNotFoundException
551 {
552 String version = reportPlugin.getVersion();
553
554 if ( version == null )
555 {
556 version = pluginVersionManager.resolveReportPluginVersion( reportPlugin.getGroupId(),
557 reportPlugin.getArtifactId(), project,
558 session.getSettings(),
559 session.getLocalRepository() );
560 reportPlugin.setVersion( version );
561 }
562
563 Plugin forLookup = new Plugin();
564
565 forLookup.setGroupId( reportPlugin.getGroupId() );
566 forLookup.setArtifactId( reportPlugin.getArtifactId() );
567 forLookup.setVersion( version );
568
569 return verifyVersionedPlugin( forLookup, project, session.getLocalRepository() );
570 }
571
572 private PlexusContainer getPluginContainer( PluginDescriptor pluginDescriptor )
573 throws PluginManagerException
574 {
575 String pluginKey = pluginDescriptor.getPluginLookupKey();
576
577 PlexusContainer pluginContainer = container.getChildContainer( pluginKey );
578
579 if ( pluginContainer == null )
580 {
581 throw new PluginManagerException( "Cannot find Plexus container for plugin: " + pluginKey );
582 }
583
584 return pluginContainer;
585 }
586
587 private Mojo getConfiguredMojo( MavenSession session,
588 Xpp3Dom dom,
589 MavenProject project,
590 boolean report,
591 MojoExecution mojoExecution )
592 throws PluginConfigurationException, ArtifactNotFoundException, PluginManagerException,
593 ArtifactResolutionException
594 {
595 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
596
597 PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
598
599 PlexusContainer pluginContainer = getPluginContainer( pluginDescriptor );
600
601 // if this is the first time this plugin has been used, the plugin's container will only
602 // contain the plugin's artifact in isolation; we need to finish resolving the plugin's
603 // dependencies, and add them to the container.
604 ensurePluginContainerIsComplete( pluginDescriptor, pluginContainer, project, session );
605
606 Mojo plugin;
607 try
608 {
609 plugin = (Mojo) pluginContainer.lookup( Mojo.ROLE, mojoDescriptor.getRoleHint() );
610 if ( report && !( plugin instanceof MavenReport ) )
611 {
612 // TODO: the mojoDescriptor should actually capture this information so we don't get this far
613 return null;
614 }
615 }
616 catch ( ComponentLookupException e )
617 {
618 throw new PluginManagerException( "Unable to find the mojo '" + mojoDescriptor.getRoleHint() +
619 "' in the plugin '" + pluginDescriptor.getPluginLookupKey() + "'", e );
620 }
621
622 if ( plugin instanceof ContextEnabled )
623 {
624 Map pluginContext = session.getPluginContext( pluginDescriptor, project );
625
626 ( (ContextEnabled) plugin ).setPluginContext( pluginContext );
627 }
628
629 plugin.setLog( mojoLogger );
630
631 XmlPlexusConfiguration pomConfiguration;
632 if ( dom == null )
633 {
634 pomConfiguration = new XmlPlexusConfiguration( "configuration" );
635 }
636 else
637 {
638 pomConfiguration = new XmlPlexusConfiguration( dom );
639 }
640
641 // Validate against non-editable (@readonly) parameters, to make sure users aren't trying to
642 // override in the POM.
643 validatePomConfiguration( mojoDescriptor, pomConfiguration );
644
645 PlexusConfiguration mergedConfiguration = mergeMojoConfiguration( pomConfiguration, mojoDescriptor );
646
647 // TODO: plexus changes to make this more like the component descriptor so this can be used instead
648 // PlexusConfiguration mergedConfiguration = mergeConfiguration( pomConfiguration,
649 // mojoDescriptor.getConfiguration() );
650
651 ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator( session, mojoExecution,
652 pathTranslator, getLogger(),
653 project,
654 session.getExecutionProperties() );
655
656 PlexusConfiguration extractedMojoConfiguration =
657 extractMojoConfiguration( mergedConfiguration, mojoDescriptor );
658
659 checkRequiredParameters( mojoDescriptor, extractedMojoConfiguration, expressionEvaluator );
660
661 populatePluginFields( plugin, mojoDescriptor, extractedMojoConfiguration, pluginContainer,
662 expressionEvaluator );
663 return plugin;
664 }
665
666 private void ensurePluginContainerIsComplete( PluginDescriptor pluginDescriptor,
667 PlexusContainer pluginContainer,
668 MavenProject project,
669 MavenSession session )
670 throws ArtifactNotFoundException, PluginManagerException, ArtifactResolutionException
671 {
672 // if the plugin's already been used once, don't re-do this step...
673 // otherwise, we have to finish resolving the plugin's classpath and start the container.
674 if ( ( pluginDescriptor.getArtifacts() != null ) && ( pluginDescriptor.getArtifacts().size() == 1 ) )
675 {
676 Artifact pluginArtifact = (Artifact) pluginDescriptor.getArtifacts().get( 0 );
677
678 ArtifactRepository localRepository = session.getLocalRepository();
679
680 ResolutionGroup resolutionGroup;
681 try
682 {
683 resolutionGroup = artifactMetadataSource.retrieve( pluginArtifact, localRepository,
684 project.getPluginArtifactRepositories() );
685 }
686 catch ( ArtifactMetadataRetrievalException e )
687 {
688 throw new ArtifactResolutionException( "Unable to download metadata from repository for plugin '" +
689 pluginArtifact.getId() + "': " + e.getMessage(), pluginArtifact, e );
690 }
691
692 checkPlexusUtils( resolutionGroup, artifactFactory );
693
694 // [jdcasey; 20-March-2008]:
695 // This is meant to eliminate the introduction of duplicated artifacts.
696 // Since much of the reasoning for reversing the order of introduction of
697 // plugin dependencies rests on the notion that we need to be able to
698 // introduce upgraded versions of plugin dependencies on a case-by-case
699 // basis, we need to remove the original version prior to artifact
700 // resolution. This is consistent with recent thinking on duplicated
701 // dependency specifications within a POM, where that case should
702 // throw a model validation exception.
703 //
704 // Here, we just want to remove any chance that the ArtifactCollector
705 // could make a bad choice, and use the old version in spite of our
706 // explicit preference otherwise.
707
708 // First, we're going to accumulate plugin dependencies in an ordered map,
709 // keyed by dependencyConflictId (the ordered map is meant to preserve relative
710 // ordering of the dependencies that do make the cut).
711 Map dependencyMap = new LinkedHashMap();
712
713 // Next, we need to accumulate all dependencies in a List, to make it
714 // simpler to iterate through them all and add them to the map.
715 List all = new ArrayList();
716
717 // plugin-level dependencies from the consuming POM override dependencies
718 // from the plugin's own POM.
719 all.addAll( pluginDescriptor.getIntroducedDependencyArtifacts() );
720
721 // add in the deps from the plugin POM now.
722 all.addAll( resolutionGroup.getArtifacts() );
723
724 for ( Iterator it = all.iterator(); it.hasNext(); )
725 {
726 Artifact artifact = (Artifact) it.next();
727 String conflictId = artifact.getDependencyConflictId();
728
729 // if the map already contains this dependencyConflictId, it constitutes an
730 // overridden dependency. Don't use the old one (we know it's old from the
731 // order in which dependencies were added to this list).
732 if ( !dependencyMap.containsKey( conflictId ) )
733 {
734 dependencyMap.put( conflictId, artifact );
735 }
736 }
737
738 // Create an ordered set of dependencies from the ordered map we used above, to feed into the resolver.
739 Set dependencies = new LinkedHashSet( dependencyMap.values() );
740
741 if ( getLogger().isDebugEnabled() )
742 {
743 // list all dependencies to be used by this plugin (first-level deps, not transitive ones).
744 getLogger().debug( "Plugin dependencies for:\n\n" + pluginDescriptor.getId()
745 + "\n\nare:\n\n"
746 + StringUtils.join( dependencies.iterator(), "\n" ) + "\n\n" );
747 }
748
749 List repositories = new ArrayList();
750 repositories.addAll( resolutionGroup.getResolutionRepositories() );
751 repositories.addAll( project.getRemoteArtifactRepositories() );
752
753 /* get plugin managed versions */
754 Map pluginManagedDependencies = new HashMap();
755 try
756 {
757 MavenProject pluginProject =
758 mavenProjectBuilder.buildFromRepository( pluginArtifact, project.getRemoteArtifactRepositories(),
759 localRepository );
760 if ( pluginProject != null )
761 {
762 pluginManagedDependencies = pluginProject.getManagedVersionMap();
763 }
764 }
765 catch ( ProjectBuildingException e )
766 {
767 // this can't happen, it would have blowed up at artifactMetadataSource.retrieve()
768 }
769
770 ArtifactResolutionResult result = artifactResolver.resolveTransitively( dependencies, pluginArtifact,
771 pluginManagedDependencies,
772 localRepository, repositories,
773 artifactMetadataSource,
774 artifactFilter );
775
776 Set resolved = result.getArtifacts();
777
778 for ( Iterator it = resolved.iterator(); it.hasNext(); )
779 {
780 Artifact artifact = (Artifact) it.next();
781
782 if ( !artifact.equals( pluginArtifact ) )
783 {
784 artifact = project.replaceWithActiveArtifact( artifact );
785
786 try
787 {
788 pluginContainer.addJarResource( artifact.getFile() );
789 }
790 catch ( PlexusContainerException e )
791 {
792 throw new PluginManagerException( "Error adding plugin dependency '" +
793 artifact.getDependencyConflictId() + "' into plugin manager: " + e.getMessage(), e );
794 }
795 }
796 }
797
798 pluginDescriptor.setClassRealm( pluginContainer.getContainerRealm() );
799
800 List unresolved = new ArrayList( dependencies );
801
802 unresolved.removeAll( resolved );
803
804 if ( getLogger().isDebugEnabled() )
805 {
806 // list all artifacts that were filtered out during the resolution process.
807 // these are already present in the core container.
808 getLogger().debug( " The following artifacts were filtered out for plugin: "
809 + pluginDescriptor.getId()
810 + " because they're already in the core of Maven:\n\n"
811 + StringUtils.join( unresolved.iterator(), "\n" )
812 + "\n\nThese will use the artifact files already in the core ClassRealm instead, to allow them to be included in PluginDescriptor.getArtifacts().\n\n" );
813 }
814
815 // Grab a file for all filtered artifacts, even if it means resolving them. This
816 // is necessary in order to present a full complement of a plugin's transitive
817 // dependencies to anyone who calls PluginDescriptor.getArtifacts().
818 resolveCoreArtifacts( unresolved, localRepository, resolutionGroup.getResolutionRepositories() );
819
820 // Re-join resolved and filtered-but-now-resolved artifacts.
821 // NOTE: The process of filtering then re-adding some artifacts will
822 // result in different ordering within the PluginDescriptor.getArtifacts()
823 // List than should have happened if none had been filtered. All filtered
824 // artifacts will be listed last...
825 List allResolved = new ArrayList( resolved.size() + unresolved.size() );
826
827 allResolved.addAll( resolved );
828 allResolved.addAll( unresolved );
829
830 pluginDescriptor.setArtifacts( allResolved );
831 }
832 }
833
834 public static void checkPlexusUtils( ResolutionGroup resolutionGroup, ArtifactFactory artifactFactory )
835 {
836 // ----------------------------------------------------------------------------
837 // If the plugin already declares a dependency on plexus-utils then we're all
838 // set as the plugin author is aware of its use. If we don't have a dependency
839 // on plexus-utils then we must protect users from stupid plugin authors who
840 // did not declare a direct dependency on plexus-utils because the version
841 // Maven uses is hidden from downstream use. We will also bump up any
842 // anything below 1.1 to 1.1 as this mimics the behaviour in 2.0.5 where
843 // plexus-utils 1.1 was being forced into use.
844 // ----------------------------------------------------------------------------
845
846 VersionRange vr = null;
847
848 try
849 {
850 vr = VersionRange.createFromVersionSpec( "[1.1,)" );
851 }
852 catch ( InvalidVersionSpecificationException e )
853 {
854 // Won't happen
855 }
856
857 boolean plexusUtilsPresent = false;
858
859 for ( Iterator i = resolutionGroup.getArtifacts().iterator(); i.hasNext(); )
860 {
861 Artifact a = (Artifact) i.next();
862
863 if ( a.getArtifactId().equals( "plexus-utils" ) &&
864 vr.containsVersion( new DefaultArtifactVersion( a.getVersion() ) ) )
865 {
866 plexusUtilsPresent = true;
867
868 break;
869 }
870 }
871
872 if ( !plexusUtilsPresent )
873 {
874 // We will add plexus-utils as every plugin was getting this anyway from Maven itself. We will set the
875 // version to the latest version we know that works as of the 2.0.6 release. We set the scope to runtime
876 // as this is what's implicitly happening in 2.0.6.
877
878 resolutionGroup.getArtifacts().add( artifactFactory.createArtifact( "org.codehaus.plexus",
879 "plexus-utils", "1.1",
880 Artifact.SCOPE_RUNTIME, "jar" ) );
881 }
882 }
883
884 private void resolveCoreArtifacts( List unresolved,
885 ArtifactRepository localRepository,
886 List resolutionRepositories )
887 throws ArtifactResolutionException, ArtifactNotFoundException
888 {
889 for ( Iterator it = unresolved.iterator(); it.hasNext(); )
890 {
891 Artifact artifact = (Artifact) it.next();
892
893 File artifactFile = (File) resolvedCoreArtifactFiles.get( artifact.getId() );
894
895 if ( artifactFile == null )
896 {
897 String resource =
898 "/META-INF/maven/" + artifact.getGroupId() + "/" + artifact.getArtifactId() + "/pom.xml";
899
900 URL resourceUrl = container.getContainerRealm().getResource( resource );
901
902 if ( resourceUrl == null )
903 {
904 artifactResolver.resolve( artifact, resolutionRepositories, localRepository );
905
906 artifactFile = artifact.getFile();
907 }
908 else
909 {
910 String artifactPath = resourceUrl.getPath();
911
912 if ( artifactPath.startsWith( "file:" ) )
913 {
914 artifactPath = artifactPath.substring( "file:".length() );
915 }
916
917 artifactPath = artifactPath.substring( 0, artifactPath.length() - resource.length() );
918
919 if ( artifactPath.endsWith( "/" ) )
920 {
921 artifactPath = artifactPath.substring( 0, artifactPath.length() - 1 );
922 }
923
924 if ( artifactPath.endsWith( "!" ) )
925 {
926 artifactPath = artifactPath.substring( 0, artifactPath.length() - 1 );
927 }
928
929 artifactFile = new File( artifactPath ).getAbsoluteFile();
930 }
931
932 resolvedCoreArtifactFiles.put( artifact.getId(), artifactFile );
933 }
934
935 artifact.setFile( artifactFile );
936 }
937 }
938
939 private PlexusConfiguration extractMojoConfiguration( PlexusConfiguration mergedConfiguration,
940 MojoDescriptor mojoDescriptor )
941 {
942 Map parameterMap = mojoDescriptor.getParameterMap();
943
944 PlexusConfiguration[] mergedChildren = mergedConfiguration.getChildren();
945
946 XmlPlexusConfiguration extractedConfiguration = new XmlPlexusConfiguration( "configuration" );
947
948 for ( int i = 0; i < mergedChildren.length; i++ )
949 {
950 PlexusConfiguration child = mergedChildren[i];
951
952 if ( parameterMap.containsKey( child.getName() ) )
953 {
954 extractedConfiguration.addChild( copyConfiguration( child ) );
955 }
956 else
957 {
958 // TODO: I defy anyone to find these messages in the '-X' output! Do we need a new log level?
959 // ideally, this would be elevated above the true debug output, but below the default INFO level...
960 // [BP] (2004-07-18): need to understand the context more but would prefer this could be either WARN or
961 // removed - shouldn't need DEBUG to diagnose a problem most of the time.
962 getLogger().debug( "*** WARNING: Configuration \'" + child.getName() + "\' is not used in goal \'" +
963 mojoDescriptor.getFullGoalName() + "; this may indicate a typo... ***" );
964 }
965 }
966
967 return extractedConfiguration;
968 }
969
970 private void checkRequiredParameters( MojoDescriptor goal,
971 PlexusConfiguration configuration,
972 ExpressionEvaluator expressionEvaluator )
973 throws PluginConfigurationException
974 {
975 // TODO: this should be built in to the configurator, as we presently double process the expressions
976
977 List parameters = goal.getParameters();
978
979 if ( parameters == null )
980 {
981 return;
982 }
983
984 List invalidParameters = new ArrayList();
985
986 for ( int i = 0; i < parameters.size(); i++ )
987 {
988 Parameter parameter = (Parameter) parameters.get( i );
989
990 if ( parameter.isRequired() )
991 {
992 // the key for the configuration map we're building.
993 String key = parameter.getName();
994
995 Object fieldValue = null;
996 String expression = null;
997 PlexusConfiguration value = configuration.getChild( key, false );
998 try
999 {
1000 if ( value != null )
1001 {
1002 expression = value.getValue( null );
1003
1004 fieldValue = expressionEvaluator.evaluate( expression );
1005
1006 if ( fieldValue == null )
1007 {
1008 fieldValue = value.getAttribute( "default-value", null );
1009 }
1010 }
1011
1012 if ( ( fieldValue == null ) && StringUtils.isNotEmpty( parameter.getAlias() ) )
1013 {
1014 value = configuration.getChild( parameter.getAlias(), false );
1015 if ( value != null )
1016 {
1017 expression = value.getValue( null );
1018 fieldValue = expressionEvaluator.evaluate( expression );
1019 if ( fieldValue == null )
1020 {
1021 fieldValue = value.getAttribute( "default-value", null );
1022 }
1023 }
1024 }
1025 }
1026 catch ( ExpressionEvaluationException e )
1027 {
1028 throw new PluginConfigurationException( goal.getPluginDescriptor(), e.getMessage(), e );
1029 }
1030
1031 // only mark as invalid if there are no child nodes
1032 if ( ( fieldValue == null ) && ( ( value == null ) || ( value.getChildCount() == 0 ) ) )
1033 {
1034 parameter.setExpression( expression );
1035 invalidParameters.add( parameter );
1036 }
1037 }
1038 }
1039
1040 if ( !invalidParameters.isEmpty() )
1041 {
1042 throw new PluginParameterException( goal, invalidParameters );
1043 }
1044 }
1045
1046 private void validatePomConfiguration( MojoDescriptor goal,
1047 PlexusConfiguration pomConfiguration )
1048 throws PluginConfigurationException
1049 {
1050 List parameters = goal.getParameters();
1051
1052 if ( parameters == null )
1053 {
1054 return;
1055 }
1056
1057 for ( int i = 0; i < parameters.size(); i++ )
1058 {
1059 Parameter parameter = (Parameter) parameters.get( i );
1060
1061 // the key for the configuration map we're building.
1062 String key = parameter.getName();
1063
1064 PlexusConfiguration value = pomConfiguration.getChild( key, false );
1065
1066 if ( ( value == null ) && StringUtils.isNotEmpty( parameter.getAlias() ) )
1067 {
1068 key = parameter.getAlias();
1069 value = pomConfiguration.getChild( key, false );
1070 }
1071
1072 if ( value != null )
1073 {
1074 // Make sure the parameter is either editable/configurable, or else is NOT specified in the POM
1075 if ( !parameter.isEditable() )
1076 {
1077 StringBuffer errorMessage = new StringBuffer()
1078 .append( "ERROR: Cannot override read-only parameter: " );
1079 errorMessage.append( key );
1080 errorMessage.append( " in goal: " ).append( goal.getFullGoalName() );
1081
1082 throw new PluginConfigurationException( goal.getPluginDescriptor(), errorMessage.toString() );
1083 }
1084
1085 String deprecated = parameter.getDeprecated();
1086 if ( StringUtils.isNotEmpty( deprecated ) )
1087 {
1088 getLogger().warn( "DEPRECATED [" + parameter.getName() + "]: " + deprecated );
1089 }
1090 }
1091 }
1092 }
1093
1094 private PlexusConfiguration mergeMojoConfiguration( XmlPlexusConfiguration fromPom,
1095 MojoDescriptor mojoDescriptor )
1096 {
1097 XmlPlexusConfiguration result = new XmlPlexusConfiguration( fromPom.getName() );
1098 result.setValue( fromPom.getValue( null ) );
1099
1100 if ( mojoDescriptor.getParameters() != null )
1101 {
1102 PlexusConfiguration fromMojo = mojoDescriptor.getMojoConfiguration();
1103
1104 for ( Iterator it = mojoDescriptor.getParameters().iterator(); it.hasNext(); )
1105 {
1106 Parameter parameter = (Parameter) it.next();
1107
1108 String paramName = parameter.getName();
1109 String alias = parameter.getAlias();
1110 String implementation = parameter.getImplementation();
1111
1112 PlexusConfiguration pomConfig = fromPom.getChild( paramName );
1113 PlexusConfiguration aliased = null;
1114
1115 if ( alias != null )
1116 {
1117 aliased = fromPom.getChild( alias );
1118 }
1119
1120 PlexusConfiguration mojoConfig = fromMojo.getChild( paramName, false );
1121
1122 // first we'll merge configurations from the aliased and real params.
1123 // TODO: Is this the right thing to do?
1124 if ( aliased != null )
1125 {
1126 if ( pomConfig == null )
1127 {
1128 pomConfig = new XmlPlexusConfiguration( paramName );
1129 }
1130
1131 pomConfig = buildTopDownMergedConfiguration( pomConfig, aliased );
1132 }
1133
1134 PlexusConfiguration toAdd = null;
1135
1136 if ( pomConfig != null )
1137 {
1138 pomConfig = buildTopDownMergedConfiguration( pomConfig, mojoConfig );
1139
1140 if ( StringUtils.isNotEmpty( pomConfig.getValue( null ) ) || ( pomConfig.getChildCount() > 0 ) )
1141 {
1142 toAdd = pomConfig;
1143 }
1144 }
1145
1146 if ( ( toAdd == null ) && ( mojoConfig != null ) )
1147 {
1148 toAdd = copyConfiguration( mojoConfig );
1149 }
1150
1151 if ( toAdd != null )
1152 {
1153 if ( ( implementation != null ) && ( toAdd.getAttribute( "implementation", null ) == null ) )
1154 {
1155
1156 XmlPlexusConfiguration implementationConf = new XmlPlexusConfiguration( paramName );
1157
1158 implementationConf.setAttribute( "implementation", parameter.getImplementation() );
1159
1160 toAdd = buildTopDownMergedConfiguration( toAdd, implementationConf );
1161 }
1162
1163 result.addChild( toAdd );
1164 }
1165 }
1166 }
1167 return result;
1168 }
1169
1170 private XmlPlexusConfiguration buildTopDownMergedConfiguration( PlexusConfiguration dominant,
1171 PlexusConfiguration recessive )
1172 {
1173 XmlPlexusConfiguration result = new XmlPlexusConfiguration( dominant.getName() );
1174
1175 String value = dominant.getValue( null );
1176
1177 if ( StringUtils.isEmpty( value ) && ( recessive != null ) )
1178 {
1179 value = recessive.getValue( null );
1180 }
1181
1182 if ( StringUtils.isNotEmpty( value ) )
1183 {
1184 result.setValue( value );
1185 }
1186
1187 String[] attributeNames = dominant.getAttributeNames();
1188
1189 for ( int i = 0; i < attributeNames.length; i++ )
1190 {
1191 String attributeValue = dominant.getAttribute( attributeNames[i], null );
1192
1193 result.setAttribute( attributeNames[i], attributeValue );
1194 }
1195
1196 if ( recessive != null )
1197 {
1198 attributeNames = recessive.getAttributeNames();
1199
1200 for ( int i = 0; i < attributeNames.length; i++ )
1201 {
1202 String attributeValue = recessive.getAttribute( attributeNames[i], null );
1203 // TODO: recessive seems to be dominant here?
1204 result.setAttribute( attributeNames[i], attributeValue );
1205 }
1206 }
1207
1208 PlexusConfiguration[] children = dominant.getChildren();
1209
1210 for ( int i = 0; i < children.length; i++ )
1211 {
1212 PlexusConfiguration childDom = children[i];
1213 PlexusConfiguration childRec = recessive == null ? null : recessive.getChild( childDom.getName(), false );
1214
1215 if ( childRec != null )
1216 {
1217 result.addChild( buildTopDownMergedConfiguration( childDom, childRec ) );
1218 }
1219 else
1220 { // FIXME: copy, or use reference?
1221 result.addChild( copyConfiguration( childDom ) );
1222 }
1223 }
1224
1225 return result;
1226 }
1227
1228 public static PlexusConfiguration copyConfiguration( PlexusConfiguration src )
1229 {
1230 // TODO: shouldn't be necessary
1231 XmlPlexusConfiguration dom = new XmlPlexusConfiguration( src.getName() );
1232 dom.setValue( src.getValue( null ) );
1233
1234 String[] attributeNames = src.getAttributeNames();
1235 for ( int i = 0; i < attributeNames.length; i++ )
1236 {
1237 String attributeName = attributeNames[i];
1238 dom.setAttribute( attributeName, src.getAttribute( attributeName, null ) );
1239 }
1240
1241 PlexusConfiguration[] children = src.getChildren();
1242 for ( int i = 0; i < children.length; i++ )
1243 {
1244 dom.addChild( copyConfiguration( children[i] ) );
1245 }
1246
1247 return dom;
1248 }
1249
1250 // ----------------------------------------------------------------------
1251 // Mojo Parameter Handling
1252 // ----------------------------------------------------------------------
1253
1254 private void populatePluginFields( Mojo plugin,
1255 MojoDescriptor mojoDescriptor,
1256 PlexusConfiguration configuration,
1257 PlexusContainer pluginContainer,
1258 ExpressionEvaluator expressionEvaluator )
1259 throws PluginConfigurationException
1260 {
1261 ComponentConfigurator configurator = null;
1262
1263 try
1264 {
1265 String configuratorId = mojoDescriptor.getComponentConfigurator();
1266
1267 // TODO: could the configuration be passed to lookup and the configurator known to plexus via the descriptor
1268 // so that this meethod could entirely be handled by a plexus lookup?
1269 if ( StringUtils.isNotEmpty( configuratorId ) )
1270 {
1271 configurator =
1272 (ComponentConfigurator) pluginContainer.lookup( ComponentConfigurator.ROLE, configuratorId );
1273 }
1274 else
1275 {
1276 configurator = (ComponentConfigurator) pluginContainer.lookup( ComponentConfigurator.ROLE );
1277 }
1278
1279 ConfigurationListener listener = new DebugConfigurationListener( getLogger() );
1280
1281 getLogger().debug( "Configuring mojo '" + mojoDescriptor.getId() + "' -->" );
1282 configurator.configureComponent( plugin, configuration, expressionEvaluator,
1283 pluginContainer.getContainerRealm(), listener );
1284 getLogger().debug( "-- end configuration --" );
1285 }
1286 catch ( ComponentConfigurationException e )
1287 {
1288 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
1289 "Unable to parse the created DOM for plugin configuration", e );
1290 }
1291 catch ( ComponentLookupException e )
1292 {
1293 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
1294 "Unable to retrieve component configurator for plugin configuration",
1295 e );
1296 }
1297 catch ( LinkageError e )
1298 {
1299 if ( getLogger().isFatalErrorEnabled() )
1300 {
1301 getLogger().fatalError(
1302 configurator.getClass().getName() + "#configureComponent(...) caused a linkage error ("
1303 + e.getClass().getName() + ") and may be out-of-date. Check the realms:" );
1304
1305 ClassRealm pluginRealm = mojoDescriptor.getPluginDescriptor().getClassRealm();
1306 StringBuffer sb = new StringBuffer();
1307 sb.append( "Plugin realm = " + pluginRealm.getId() ).append( '\n' );
1308 for ( int i = 0; i < pluginRealm.getConstituents().length; i++ )
1309 {
1310 sb.append( "urls[" + i + "] = " + pluginRealm.getConstituents()[i] );
1311 if ( i != ( pluginRealm.getConstituents().length - 1 ) )
1312 {
1313 sb.append( '\n' );
1314 }
1315 }
1316 getLogger().fatalError( sb.toString() );
1317
1318 ClassRealm containerRealm = container.getContainerRealm();
1319 sb = new StringBuffer();
1320 sb.append( "Container realm = " + containerRealm.getId() ).append( '\n' );
1321 for ( int i = 0; i < containerRealm.getConstituents().length; i++ )
1322 {
1323 sb.append( "urls[" + i + "] = " + containerRealm.getConstituents()[i] );
1324 if ( i != ( containerRealm.getConstituents().length - 1 ) )
1325 {
1326 sb.append( '\n' );
1327 }
1328 }
1329 getLogger().fatalError( sb.toString() );
1330 }
1331
1332 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
1333 e.getClass().getName() + ": " + e.getMessage(), e );
1334 }
1335 finally
1336 {
1337 if ( configurator != null )
1338 {
1339 try
1340 {
1341 pluginContainer.release( configurator );
1342 }
1343 catch ( ComponentLifecycleException e )
1344 {
1345 getLogger().debug( "Failed to release plugin container - ignoring." );
1346 }
1347 }
1348 }
1349 }
1350
1351 public static String createPluginParameterRequiredMessage( MojoDescriptor mojo,
1352 Parameter parameter,
1353 String expression )
1354 {
1355 StringBuffer message = new StringBuffer();
1356
1357 message.append( "The '" );
1358 message.append( parameter.getName() );
1359 message.append( "' parameter is required for the execution of the " );
1360 message.append( mojo.getFullGoalName() );
1361 message.append( " mojo and cannot be null." );
1362 if ( expression != null )
1363 {
1364 message.append( " The retrieval expression was: " ).append( expression );
1365 }
1366
1367 return message.toString();
1368 }
1369
1370 // ----------------------------------------------------------------------
1371 // Lifecycle
1372 // ----------------------------------------------------------------------
1373
1374 public void contextualize( Context context )
1375 throws ContextException
1376 {
1377 container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
1378
1379 mojoLogger = new DefaultLog( container.getLoggerManager().getLoggerForComponent( Mojo.ROLE ) );
1380 }
1381
1382 public void initialize()
1383 {
1384 artifactFilter = MavenArtifactFilterManager.createStandardFilter();
1385 }
1386
1387 // ----------------------------------------------------------------------
1388 // Artifact resolution
1389 // ----------------------------------------------------------------------
1390
1391 private void resolveTransitiveDependencies( MavenSession context,
1392 ArtifactResolver artifactResolver,
1393 String scope,
1394 ArtifactFactory artifactFactory,
1395 MavenProject project, boolean isAggregator )
1396 throws ArtifactResolutionException, ArtifactNotFoundException, InvalidDependencyVersionException
1397 {
1398 ArtifactFilter filter = new ScopeArtifactFilter( scope );
1399
1400 // TODO: such a call in MavenMetadataSource too - packaging not really the intention of type
1401 Artifact artifact = artifactFactory.createBuildArtifact( project.getGroupId(), project.getArtifactId(),
1402 project.getVersion(), project.getPackaging() );
1403
1404 // TODO: we don't need to resolve over and over again, as long as we are sure that the parameters are the same
1405 // check this with yourkit as a hot spot.
1406 // Don't recreate if already created - for effeciency, and because clover plugin adds to it
1407 if ( project.getDependencyArtifacts() == null )
1408 {
1409 project.setDependencyArtifacts( project.createArtifacts( artifactFactory, null, null ) );
1410 }
1411
1412 Set resolvedArtifacts;
1413 try
1414 {
1415 ArtifactResolutionResult result = artifactResolver.resolveTransitively( project.getDependencyArtifacts(),
1416 artifact,
1417 project.getManagedVersionMap(),
1418 context.getLocalRepository(),
1419 project.getRemoteArtifactRepositories(),
1420 artifactMetadataSource, filter );
1421 resolvedArtifacts = result.getArtifacts();
1422 }
1423 catch (MultipleArtifactsNotFoundException me)
1424 {
1425 /*only do this if we are an aggregating plugin: MNG-2277
1426 if the dependency doesn't yet exist but is in the reactor, then
1427 all we can do is warn and skip it. A better fix can be inserted into 2.1*/
1428 if (isAggregator && checkMissingArtifactsInReactor( context.getSortedProjects(), me.getMissingArtifacts() ))
1429 {
1430 resolvedArtifacts = new HashSet(me.getResolvedArtifacts());
1431 }
1432 else
1433 {
1434 //we can't find all the artifacts in the reactor so bubble the exception up.
1435 throw me;
1436 }
1437 }
1438 project.setArtifacts( resolvedArtifacts );
1439 }
1440
1441 /**
1442 * This method is checking to see if the artifacts that can't be resolved are all
1443 * part of this reactor. This is done to prevent a chicken or egg scenario with
1444 * fresh projects that have a plugin that is an aggregator and requires dependencies. See
1445 * MNG-2277 for more info.
1446 * @param projects the sibling projects in the reactor
1447 * @param missing the artifacts that can't be found
1448 * @return true if ALL missing artifacts are found in the reactor.
1449 */
1450 private boolean checkMissingArtifactsInReactor(Collection projects, Collection missing)
1451 {
1452 Collection foundInReactor = new HashSet();
1453 Iterator iter = missing.iterator();
1454 while (iter.hasNext())
1455 {
1456 Artifact mArtifact = (Artifact) iter.next();
1457 Iterator pIter = projects.iterator();
1458 while (pIter.hasNext())
1459 {
1460 MavenProject p = (MavenProject) pIter.next();
1461 if (p.getArtifactId().equals( mArtifact.getArtifactId()) &&
1462 p.getGroupId().equals( mArtifact.getGroupId()) &&
1463 p.getVersion().equals( mArtifact.getVersion()))
1464 {
1465 //TODO: the packaging could be different, but the exception doesn't contain that info
1466 //most likely it would be produced by the project we just found in the reactor since all
1467 //the other info matches. Assume it's ok.
1468 getLogger().warn( "The dependency: "+ p.getId()+" can't be resolved but has been found in the reactor.\nThis dependency has been excluded from the plugin execution. You should rerun this mojo after executing mvn install.\n" );
1469
1470 //found it, move on.
1471 foundInReactor.add( p );
1472 break;
1473 }
1474 }
1475 }
1476
1477 //if all of them have been found, we can continue.
1478 return foundInReactor.size() == missing.size();
1479 }
1480
1481
1482 // ----------------------------------------------------------------------
1483 // Artifact downloading
1484 // ----------------------------------------------------------------------
1485
1486 private void downloadDependencies( MavenProject project,
1487 MavenSession context,
1488 ArtifactResolver artifactResolver )
1489 throws ArtifactResolutionException, ArtifactNotFoundException
1490 {
1491 ArtifactRepository localRepository = context.getLocalRepository();
1492 List remoteArtifactRepositories = project.getRemoteArtifactRepositories();
1493
1494 for ( Iterator it = project.getArtifacts().iterator(); it.hasNext(); )
1495 {
1496 Artifact artifact = (Artifact) it.next();
1497
1498 artifactResolver.resolve( artifact, remoteArtifactRepositories, localRepository );
1499 }
1500 }
1501
1502 public Object getPluginComponent( Plugin plugin,
1503 String role,
1504 String roleHint )
1505 throws PluginManagerException, ComponentLookupException
1506 {
1507 PluginDescriptor pluginDescriptor = pluginCollector.getPluginDescriptor( plugin );
1508
1509 PlexusContainer pluginContainer = getPluginContainer( pluginDescriptor );
1510
1511 return pluginContainer.lookup( role, roleHint );
1512 }
1513
1514 public Map getPluginComponents( Plugin plugin,
1515 String role )
1516 throws ComponentLookupException, PluginManagerException
1517 {
1518 PluginDescriptor pluginDescriptor = pluginCollector.getPluginDescriptor( plugin );
1519
1520 PlexusContainer pluginContainer = getPluginContainer( pluginDescriptor );
1521
1522 return pluginContainer.lookupMap( role );
1523 }
1524 }