blob: a11e02ab90a2200096ead04022332d1f63b3f849 [file] [log] [blame]
package org.apache.maven.plugin;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import static org.apache.maven.container.ContainerUtils.findChildComponentHints;
import org.apache.maven.MavenArtifactFilterManager;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.metadata.ResolutionGroup;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.RuntimeInformation;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.ReportPlugin;
import org.apache.maven.monitor.event.EventDispatcher;
import org.apache.maven.monitor.event.MavenEvents;
import org.apache.maven.monitor.logging.DefaultLog;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.Parameter;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugin.version.PluginVersionManager;
import org.apache.maven.plugin.version.PluginVersionNotFoundException;
import org.apache.maven.plugin.version.PluginVersionResolutionException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.artifact.InvalidDependencyVersionException;
import org.apache.maven.project.artifact.MavenMetadataSource;
import org.apache.maven.project.path.PathTranslator;
import org.apache.maven.reporting.MavenReport;
import org.apache.maven.settings.Settings;
import org.apache.maven.wagon.Wagon;
import org.codehaus.classworlds.ClassRealm;
import org.codehaus.classworlds.NoSuchRealmException;
import org.codehaus.plexus.PlexusConstants;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.PlexusContainerException;
import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
import org.codehaus.plexus.component.configurator.ComponentConfigurator;
import org.codehaus.plexus.component.configurator.ConfigurationListener;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
import org.codehaus.plexus.component.discovery.ComponentDiscoveryListener;
import org.codehaus.plexus.component.repository.ComponentDescriptor;
import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.configuration.PlexusConfiguration;
import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
import org.codehaus.plexus.context.Context;
import org.codehaus.plexus.context.ContextException;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class DefaultPluginManager
extends AbstractLogEnabled
implements PluginManager, Initializable, Contextualizable
{
protected PlexusContainer container;
protected PluginDescriptorBuilder pluginDescriptorBuilder;
protected ArtifactFilter artifactFilter;
private Log mojoLogger;
private Map resolvedCoreArtifactFiles = new HashMap();
// component requirements
protected PathTranslator pathTranslator;
protected MavenPluginCollector pluginCollector;
protected PluginVersionManager pluginVersionManager;
protected ArtifactFactory artifactFactory;
protected ArtifactResolver artifactResolver;
protected ArtifactMetadataSource artifactMetadataSource;
protected RuntimeInformation runtimeInformation;
protected MavenProjectBuilder mavenProjectBuilder;
protected PluginMappingManager pluginMappingManager;
// END component requirements
public DefaultPluginManager()
{
pluginDescriptorBuilder = new PluginDescriptorBuilder();
}
// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
public PluginDescriptor getPluginDescriptorForPrefix( String prefix )
{
return pluginCollector.getPluginDescriptorForPrefix( prefix );
}
public Plugin getPluginDefinitionForPrefix( String prefix,
MavenSession session,
MavenProject project )
{
// TODO: since this is only used in the lifecycle executor, maybe it should be moved there? There is no other
// use for the mapping manager in here
return pluginMappingManager.getByPrefix( prefix, session.getSettings().getPluginGroups(),
project.getPluginArtifactRepositories(),
session.getLocalRepository() );
}
/**
* {@inheritDoc}
*/
public PluginDescriptor verifyPlugin( Plugin plugin,
MavenProject project,
Settings settings,
ArtifactRepository localRepository )
throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
PluginVersionNotFoundException
{
// TODO: this should be possibly outside
// All version-resolution logic has been moved to DefaultPluginVersionManager.
if ( plugin.getVersion() == null )
{
String version = pluginVersionManager.resolvePluginVersion( plugin.getGroupId(), plugin.getArtifactId(),
project, settings, localRepository );
plugin.setVersion( version );
}
return verifyVersionedPlugin( plugin, project, localRepository );
}
private PluginDescriptor verifyVersionedPlugin( Plugin plugin,
MavenProject project,
ArtifactRepository localRepository )
throws PluginVersionResolutionException, ArtifactNotFoundException, ArtifactResolutionException,
InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException
{
// TODO: this might result in an artifact "RELEASE" being resolved continuously
// FIXME: need to find out how a plugin gets marked as 'installed'
// and no ChildContainer exists. The check for that below fixes
// the 'Can't find plexus container for plugin: xxx' error.
try
{
VersionRange versionRange = VersionRange.createFromVersionSpec( plugin.getVersion() );
List remoteRepositories = new ArrayList();
remoteRepositories.addAll( project.getPluginArtifactRepositories() );
remoteRepositories.addAll( project.getRemoteArtifactRepositories() );
checkRequiredMavenVersion( plugin, localRepository, remoteRepositories );
Artifact pluginArtifact =
artifactFactory.createPluginArtifact( plugin.getGroupId(), plugin.getArtifactId(), versionRange );
pluginArtifact = project.replaceWithActiveArtifact( pluginArtifact );
artifactResolver.resolve( pluginArtifact, project.getPluginArtifactRepositories(), localRepository );
plugin.setVersion( pluginArtifact.getBaseVersion() );
String pluginKey = PluginUtils.constructVersionedKey( plugin );
PlexusContainer pluginContainer = container.getChildContainer( pluginKey );
File pluginFile = pluginArtifact.getFile();
if ( !pluginCollector.isPluginInstalled( plugin ) || ( pluginContainer == null ) )
{
addPlugin( plugin, pluginArtifact, project, localRepository );
}
else if ( pluginFile.lastModified() > pluginContainer.getCreationDate().getTime() )
{
getLogger().info(
"Reloading plugin container for: " + pluginKey + ". The plugin artifact has changed." );
pluginContainer.dispose();
pluginCollector.flushPluginDescriptor( plugin );
addPlugin( plugin, pluginArtifact, project, localRepository );
}
project.addPlugin( plugin );
}
catch ( ArtifactNotFoundException e )
{
String groupId = plugin.getGroupId();
String artifactId = plugin.getArtifactId();
String version = plugin.getVersion();
if ( ( groupId == null ) || ( artifactId == null ) || ( version == null ) )
{
throw new PluginNotFoundException( e );
}
else if ( groupId.equals( e.getGroupId() ) && artifactId.equals( e.getArtifactId() ) &&
version.equals( e.getVersion() ) && "maven-plugin".equals( e.getType() ) )
{
throw new PluginNotFoundException( e );
}
else
{
throw e;
}
}
return pluginCollector.getPluginDescriptor( plugin );
}
/**
* @todo would be better to store this in the plugin descriptor, but then it won't be available to the version
* manager which executes before the plugin is instantiated
*/
private void checkRequiredMavenVersion( Plugin plugin,
ArtifactRepository localRepository,
List remoteRepositories )
throws PluginVersionResolutionException, InvalidPluginException
{
try
{
Artifact artifact = artifactFactory.createProjectArtifact( plugin.getGroupId(), plugin.getArtifactId(),
plugin.getVersion() );
MavenProject project =
mavenProjectBuilder.buildFromRepository( artifact, remoteRepositories, localRepository, false );
// if we don't have the required Maven version, then ignore an update
if ( ( project.getPrerequisites() != null ) && ( project.getPrerequisites().getMaven() != null ) )
{
DefaultArtifactVersion requiredVersion =
new DefaultArtifactVersion( project.getPrerequisites().getMaven() );
if ( runtimeInformation.getApplicationVersion().compareTo( requiredVersion ) < 0 )
{
throw new PluginVersionResolutionException( plugin.getGroupId(), plugin.getArtifactId(),
"Plugin requires Maven version " + requiredVersion );
}
}
}
catch ( ProjectBuildingException e )
{
throw new InvalidPluginException(
"Unable to build project for plugin '" + plugin.getKey() + "': " + e.getMessage(), e );
}
}
protected void addPlugin( Plugin plugin,
Artifact pluginArtifact,
MavenProject project,
ArtifactRepository localRepository )
throws PluginManagerException, InvalidPluginException
{
PlexusContainer child;
try
{
MavenPluginValidator validator = new MavenPluginValidator( pluginArtifact );
String key = PluginUtils.constructVersionedKey( plugin ).intern();
child = container.createChildContainer( key,
Collections.singletonList( pluginArtifact.getFile() ),
Collections.EMPTY_MAP,
Arrays.asList( new ComponentDiscoveryListener[] { validator, pluginCollector } ) );
// remove listeners for efficiency since they are only needed for the initial stage and
// should not be applied to the plugin's dependencies
child.removeComponentDiscoveryListener( validator );
child.removeComponentDiscoveryListener( pluginCollector );
if ( validator.hasErrors() )
{
String msg = "Plugin '" + key + "' has an invalid descriptor:";
int count = 1;
for ( Iterator i = validator.getErrors().iterator(); i.hasNext(); )
{
msg += "\n" + count + ") " + i.next();
count++;
}
throw new PluginManagerException( msg );
}
try
{
child.getContainerRealm().importFrom( "plexus.core", "org.codehaus.plexus.util.xml.Xpp3Dom" );
child.getContainerRealm().importFrom( "plexus.core", "org.codehaus.plexus.util.xml.pull.XmlPullParser" );
child.getContainerRealm().importFrom( "plexus.core", "org.codehaus.plexus.util.xml.pull.XmlPullParserException" );
child.getContainerRealm().importFrom( "plexus.core", "org.codehaus.plexus.util.xml.pull.XmlSerializer" );
// MNG-2878
child.getContainerRealm().importFrom( "plexus.core", "/default-report.xml" );
}
catch ( NoSuchRealmException e )
{
// won't happen
}
}
catch ( PlexusContainerException e )
{
throw new PluginManagerException(
"Failed to create plugin container for plugin '" + plugin + "': " + e.getMessage(), e );
}
// this plugin's descriptor should have been discovered in the child creation, so we should be able to
// circle around and set the artifacts and class realm
PluginDescriptor addedPlugin = pluginCollector.getPluginDescriptor( plugin );
if ( addedPlugin == null )
{
throw new IllegalStateException( "The plugin descriptor for the plugin " + plugin + " was not found."
+ " Please verify that the plugin JAR " + pluginArtifact.getFile() + " is intact." );
}
addedPlugin.setClassRealm( child.getContainerRealm() );
// we're only setting the plugin's artifact itself as the artifact list, to allow it to be retrieved
// later when the plugin is first invoked. Retrieving this artifact will in turn allow us to
// transitively resolve its dependencies, and add them to the plugin container...
addedPlugin.setArtifacts( Collections.singletonList( pluginArtifact ) );
addedPlugin.setPluginArtifact( pluginArtifact );
try
{
// the only Plugin instance which will have dependencies is the one specified in the project.
// We need to look for a Plugin instance there, in case the instance we're using didn't come from
// the project.
Plugin projectPlugin = (Plugin) project.getBuild().getPluginsAsMap().get( plugin.getKey() );
if ( projectPlugin == null )
{
projectPlugin = plugin;
}
Set artifacts = MavenMetadataSource.createArtifacts( artifactFactory, projectPlugin.getDependencies(), null,
null, project );
// Set artifacts =
// MavenMetadataSource.createArtifacts( artifactFactory, plugin.getDependencies(), null, null, project );
addedPlugin.setIntroducedDependencyArtifacts( artifacts );
}
catch ( InvalidDependencyVersionException e )
{
throw new InvalidPluginException( "Plugin '" + plugin + "' is invalid: " + e.getMessage(), e );
}
}
// ----------------------------------------------------------------------
// Mojo execution
// ----------------------------------------------------------------------
public void executeMojo( MavenProject project,
MojoExecution mojoExecution,
MavenSession session )
throws ArtifactResolutionException, MojoExecutionException, MojoFailureException, ArtifactNotFoundException,
InvalidDependencyVersionException, PluginManagerException, PluginConfigurationException
{
MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
// NOTE: I'm putting these checks in here, since this is the central point of access for
// anything that wants to execute a mojo.
if ( mojoDescriptor.isProjectRequired() && !session.isUsingPOMsFromFilesystem() )
{
throw new MojoExecutionException( "Cannot execute mojo: " + mojoDescriptor.getGoal() +
". It requires a project with an existing pom.xml, but the build is not using one." );
}
if ( mojoDescriptor.isOnlineRequired() && session.getSettings().isOffline() )
{
// TODO: Should we error out, or simply warn and skip??
throw new MojoExecutionException( "Mojo: " + mojoDescriptor.getGoal() +
" requires online mode for execution. Maven is currently offline." );
}
if ( mojoDescriptor.isDependencyResolutionRequired() != null )
{
Collection projects;
if ( mojoDescriptor.isAggregator() )
{
projects = session.getSortedProjects();
}
else
{
projects = Collections.singleton( project );
}
for ( Iterator i = projects.iterator(); i.hasNext(); )
{
MavenProject p = (MavenProject) i.next();
resolveTransitiveDependencies( session, artifactResolver,
mojoDescriptor.isDependencyResolutionRequired(), artifactFactory, p, mojoDescriptor.isAggregator() );
}
downloadDependencies( project, session, artifactResolver );
}
String goalName = mojoDescriptor.getFullGoalName();
Mojo plugin;
PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
String goalId = mojoDescriptor.getGoal();
String groupId = pluginDescriptor.getGroupId();
String artifactId = pluginDescriptor.getArtifactId();
String executionId = mojoExecution.getExecutionId();
Xpp3Dom dom = project.getGoalConfiguration( groupId, artifactId, executionId, goalId );
Xpp3Dom reportDom = project.getReportConfiguration( groupId, artifactId, executionId );
dom = Xpp3Dom.mergeXpp3Dom( dom, reportDom );
if ( mojoExecution.getConfiguration() != null )
{
dom = Xpp3Dom.mergeXpp3Dom( dom, mojoExecution.getConfiguration() );
}
plugin = getConfiguredMojo( session, dom, project, false, mojoExecution );
// Event monitoring.
String event = MavenEvents.MOJO_EXECUTION;
EventDispatcher dispatcher = session.getEventDispatcher();
String goalExecId = goalName;
if ( mojoExecution.getExecutionId() != null )
{
goalExecId += " {execution: " + mojoExecution.getExecutionId() + "}";
}
dispatcher.dispatchStart( event, goalExecId );
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(
mojoDescriptor.getPluginDescriptor().getClassRealm().getClassLoader() );
plugin.execute();
dispatcher.dispatchEnd( event, goalExecId );
}
catch ( MojoExecutionException e )
{
session.getEventDispatcher().dispatchError( event, goalExecId, e );
throw e;
}
catch ( MojoFailureException e )
{
session.getEventDispatcher().dispatchError( event, goalExecId, e );
throw e;
}
catch ( LinkageError e )
{
if ( getLogger().isFatalErrorEnabled() )
{
getLogger().fatalError(
plugin.getClass().getName() + "#execute() caused a linkage error ("
+ e.getClass().getName() + ") and may be out-of-date. Check the realms:" );
ClassRealm pluginRealm = mojoDescriptor.getPluginDescriptor().getClassRealm();
StringBuffer sb = new StringBuffer();
sb.append( "Plugin realm = " + pluginRealm.getId() ).append( '\n' );
for ( int i = 0; i < pluginRealm.getConstituents().length; i++ )
{
sb.append( "urls[" + i + "] = " + pluginRealm.getConstituents()[i] );
if ( i != ( pluginRealm.getConstituents().length - 1 ) )
{
sb.append( '\n' );
}
}
getLogger().fatalError( sb.toString() );
ClassRealm containerRealm = container.getContainerRealm();
sb = new StringBuffer();
sb.append( "Container realm = " + containerRealm.getId() ).append( '\n' );
for ( int i = 0; i < containerRealm.getConstituents().length; i++ )
{
sb.append( "urls[" + i + "] = " + containerRealm.getConstituents()[i] );
if ( i != ( containerRealm.getConstituents().length - 1 ) )
{
sb.append( '\n' );
}
}
getLogger().fatalError( sb.toString() );
}
session.getEventDispatcher().dispatchError( event, goalExecId, e );
throw e;
}
finally
{
Thread.currentThread().setContextClassLoader( oldClassLoader );
try
{
PlexusContainer pluginContainer = getPluginContainer( mojoDescriptor.getPluginDescriptor() );
pluginContainer.release( plugin );
}
catch ( ComponentLifecycleException e )
{
if ( getLogger().isErrorEnabled() )
{
getLogger().error( "Error releasing plugin - ignoring.", e );
}
}
}
}
public MavenReport getReport( MavenProject project,
MojoExecution mojoExecution,
MavenSession session )
throws ArtifactNotFoundException, PluginConfigurationException, PluginManagerException,
ArtifactResolutionException
{
MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
PluginDescriptor descriptor = mojoDescriptor.getPluginDescriptor();
Xpp3Dom dom = project.getReportConfiguration( descriptor.getGroupId(), descriptor.getArtifactId(),
mojoExecution.getExecutionId() );
if ( mojoExecution.getConfiguration() != null )
{
dom = Xpp3Dom.mergeXpp3Dom( dom, mojoExecution.getConfiguration() );
}
MavenReport report = (MavenReport) getConfiguredMojo( session, dom, project, true, mojoExecution );
return report;
}
public PluginDescriptor verifyReportPlugin( ReportPlugin reportPlugin,
MavenProject project,
MavenSession session )
throws PluginVersionResolutionException, ArtifactResolutionException, ArtifactNotFoundException,
InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
PluginVersionNotFoundException
{
String version = reportPlugin.getVersion();
if ( version == null )
{
version = pluginVersionManager.resolveReportPluginVersion( reportPlugin.getGroupId(),
reportPlugin.getArtifactId(), project,
session.getSettings(),
session.getLocalRepository() );
reportPlugin.setVersion( version );
}
Plugin forLookup = new Plugin();
forLookup.setGroupId( reportPlugin.getGroupId() );
forLookup.setArtifactId( reportPlugin.getArtifactId() );
forLookup.setVersion( version );
return verifyVersionedPlugin( forLookup, project, session.getLocalRepository() );
}
private PlexusContainer getPluginContainer( PluginDescriptor pluginDescriptor )
throws PluginManagerException
{
String pluginKey = PluginUtils.constructVersionedKey( pluginDescriptor );
PlexusContainer pluginContainer = container.getChildContainer( pluginKey );
if ( pluginContainer == null )
{
throw new PluginManagerException( "Cannot find Plexus container for plugin: " + pluginKey );
}
return pluginContainer;
}
private Mojo getConfiguredMojo( MavenSession session,
Xpp3Dom dom,
MavenProject project,
boolean report,
MojoExecution mojoExecution )
throws PluginConfigurationException, ArtifactNotFoundException, PluginManagerException,
ArtifactResolutionException
{
MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
PlexusContainer pluginContainer = getPluginContainer( pluginDescriptor );
// if this is the first time this plugin has been used, the plugin's container will only
// contain the plugin's artifact in isolation; we need to finish resolving the plugin's
// dependencies, and add them to the container.
ensurePluginContainerIsComplete( pluginDescriptor, pluginContainer, project, session );
Mojo plugin;
try
{
plugin = (Mojo) pluginContainer.lookup( Mojo.ROLE, mojoDescriptor.getRoleHint() );
if ( report && !( plugin instanceof MavenReport ) )
{
// TODO: the mojoDescriptor should actually capture this information so we don't get this far
return null;
}
}
catch ( ComponentLookupException e )
{
Throwable cause = e.getCause();
while( cause != null && !(cause instanceof NoClassDefFoundError ) )
{
cause = cause.getCause();
}
if ( cause != null && ( cause instanceof NoClassDefFoundError ) )
{
throw new PluginManagerException( "Unable to load the mojo '" + mojoDescriptor.getRoleHint()
+ "' in the plugin '" + pluginDescriptor.getPluginLookupKey() + "'. A required class is missing: "
+ cause.getMessage(), e );
}
throw new PluginManagerException( "Unable to find the mojo '" + mojoDescriptor.getGoal() +
"' (or one of its required components) in the plugin '" + pluginDescriptor.getPluginLookupKey() + "'", e );
}
catch ( NoClassDefFoundError e )
{
throw new PluginManagerException( "Unable to load the mojo '" + mojoDescriptor.getRoleHint()
+ "' in the plugin '" + pluginDescriptor.getPluginLookupKey() + "'. A required class is missing: "
+ e.getMessage(), e );
}
if ( plugin instanceof ContextEnabled )
{
Map pluginContext = session.getPluginContext( pluginDescriptor, project );
( (ContextEnabled) plugin ).setPluginContext( pluginContext );
}
plugin.setLog( mojoLogger );
XmlPlexusConfiguration pomConfiguration;
if ( dom == null )
{
pomConfiguration = new XmlPlexusConfiguration( "configuration" );
}
else
{
pomConfiguration = new XmlPlexusConfiguration( dom );
}
// Validate against non-editable (@readonly) parameters, to make sure users aren't trying to
// override in the POM.
validatePomConfiguration( mojoDescriptor, pomConfiguration );
PlexusConfiguration mergedConfiguration = mergeMojoConfiguration( pomConfiguration, mojoDescriptor );
// TODO: plexus changes to make this more like the component descriptor so this can be used instead
// PlexusConfiguration mergedConfiguration = mergeConfiguration( pomConfiguration,
// mojoDescriptor.getConfiguration() );
ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator( session, mojoExecution,
pathTranslator,
getLogger(),
project,
session.getExecutionProperties() );
PlexusConfiguration extractedMojoConfiguration =
extractMojoConfiguration( mergedConfiguration, mojoDescriptor );
checkRequiredParameters( mojoDescriptor, extractedMojoConfiguration, expressionEvaluator );
populatePluginFields( plugin, mojoDescriptor, extractedMojoConfiguration, pluginContainer,
expressionEvaluator );
return plugin;
}
private void ensurePluginContainerIsComplete( PluginDescriptor pluginDescriptor,
PlexusContainer pluginContainer,
MavenProject project,
MavenSession session )
throws ArtifactNotFoundException, PluginManagerException, ArtifactResolutionException
{
// if the plugin's already been used once, don't re-do this step...
// otherwise, we have to finish resolving the plugin's classpath and start the container.
if ( ( pluginDescriptor.getArtifacts() != null ) && ( pluginDescriptor.getArtifacts().size() == 1 ) )
{
Artifact pluginArtifact = (Artifact) pluginDescriptor.getArtifacts().get( 0 );
ArtifactRepository localRepository = session.getLocalRepository();
ArtifactMetadataSource metadataSource = session.getProjectBuilderConfiguration().getMetadataSource();
if ( metadataSource == null )
{
metadataSource = artifactMetadataSource;
}
ResolutionGroup resolutionGroup;
try
{
resolutionGroup = metadataSource.retrieve( pluginArtifact, localRepository,
project.getPluginArtifactRepositories() );
}
catch ( ArtifactMetadataRetrievalException e )
{
throw new ArtifactResolutionException( "Unable to download metadata from repository for plugin '" +
pluginArtifact.getId() + "': " + e.getMessage(), pluginArtifact, e );
}
Set rgArtifacts = resolutionGroup.getArtifacts();
rgArtifacts = checkPlexusUtils( rgArtifacts, artifactFactory );
// [jdcasey; 20-March-2008]:
// This is meant to eliminate the introduction of duplicated artifacts.
// Since much of the reasoning for reversing the order of introduction of
// plugin dependencies rests on the notion that we need to be able to
// introduce upgraded versions of plugin dependencies on a case-by-case
// basis, we need to remove the original version prior to artifact
// resolution. This is consistent with recent thinking on duplicated
// dependency specifications within a POM, where that case should
// throw a model validation exception.
//
// Here, we just want to remove any chance that the ArtifactCollector
// could make a bad choice, and use the old version in spite of our
// explicit preference otherwise.
// First, we're going to accumulate plugin dependencies in an ordered map,
// keyed by dependencyConflictId (the ordered map is meant to preserve relative
// ordering of the dependencies that do make the cut).
Map dependencyMap = new LinkedHashMap();
// Next, we need to accumulate all dependencies in a List, to make it
// simpler to iterate through them all and add them to the map.
List all = new ArrayList();
// plugin-level dependencies from the consuming POM override dependencies
// from the plugin's own POM.
all.addAll( pluginDescriptor.getIntroducedDependencyArtifacts() );
// add in the deps from the plugin POM now.
all.addAll( rgArtifacts );
for ( Iterator it = all.iterator(); it.hasNext(); )
{
Artifact artifact = (Artifact) it.next();
String conflictId = artifact.getDependencyConflictId();
// if the map already contains this dependencyConflictId, it constitutes an
// overridden dependency. Don't use the old one (we know it's old from the
// order in which dependencies were added to this list).
if ( !dependencyMap.containsKey( conflictId ) )
{
dependencyMap.put( conflictId, artifact );
}
}
// Create an ordered set of dependencies from the ordered map we used above, to feed into the resolver.
Set dependencies = new LinkedHashSet( dependencyMap.values() );
if ( getLogger().isDebugEnabled() )
{
// list all dependencies to be used by this plugin (first-level deps, not transitive ones).
getLogger().debug( "Plugin dependencies for:\n\n" + pluginDescriptor.getId()
+ "\n\nare:\n\n"
+ StringUtils.join( dependencies.iterator(), "\n" ) + "\n\n" );
}
List repositories = new ArrayList();
repositories.addAll( resolutionGroup.getResolutionRepositories() );
repositories.addAll( project.getRemoteArtifactRepositories() );
/* get plugin managed versions */
Map pluginManagedDependencies = new HashMap();
try
{
MavenProject pluginProject =
mavenProjectBuilder.buildFromRepository( pluginArtifact, project.getRemoteArtifactRepositories(),
localRepository );
if ( pluginProject != null )
{
pluginManagedDependencies = pluginProject.getManagedVersionMap();
}
}
catch ( ProjectBuildingException e )
{
// this can't happen, it would have blowed up at artifactMetadataSource.retrieve()
}
ArtifactResolutionResult result = artifactResolver.resolveTransitively( dependencies, pluginArtifact,
pluginManagedDependencies,
localRepository, repositories,
metadataSource,
artifactFilter );
Set resolved = result.getArtifacts();
for ( Iterator it = resolved.iterator(); it.hasNext(); )
{
Artifact artifact = (Artifact) it.next();
if ( !artifact.equals( pluginArtifact ) )
{
artifact = project.replaceWithActiveArtifact( artifact );
try
{
pluginContainer.addJarResource( artifact.getFile() );
}
catch ( PlexusContainerException e )
{
throw new PluginManagerException( "Error adding plugin dependency '" +
artifact.getDependencyConflictId() + "' into plugin manager: " + e.getMessage(), e );
}
}
}
pluginDescriptor.setClassRealm( pluginContainer.getContainerRealm() );
List unresolved = new ArrayList( dependencies );
unresolved.removeAll( resolved );
if ( getLogger().isDebugEnabled() )
{
// list all artifacts that were filtered out during the resolution process.
// these are already present in the core container.
getLogger().debug( " The following artifacts were filtered out for plugin: "
+ pluginDescriptor.getId()
+ " because they're already in the core of Maven:\n\n"
+ StringUtils.join( unresolved.iterator(), "\n" )
+ "\n\nThese will use the artifact files already in the core ClassRealm instead, to allow them to be included in PluginDescriptor.getArtifacts().\n\n" );
}
// Grab a file for all filtered artifacts, even if it means resolving them. This
// is necessary in order to present a full complement of a plugin's transitive
// dependencies to anyone who calls PluginDescriptor.getArtifacts().
resolveCoreArtifacts( unresolved, localRepository, resolutionGroup.getResolutionRepositories() );
// Re-join resolved and filtered-but-now-resolved artifacts.
// NOTE: The process of filtering then re-adding some artifacts will
// result in different ordering within the PluginDescriptor.getArtifacts()
// List than should have happened if none had been filtered. All filtered
// artifacts will be listed last...
List allResolved = new ArrayList( resolved.size() + unresolved.size() );
allResolved.addAll( resolved );
allResolved.addAll( unresolved );
pluginDescriptor.setArtifacts( allResolved );
}
}
public static Set checkPlexusUtils( Set dependencyArtifacts, ArtifactFactory artifactFactory )
{
// ----------------------------------------------------------------------------
// If the plugin already declares a dependency on plexus-utils then we're all
// set as the plugin author is aware of its use. If we don't have a dependency
// on plexus-utils then we must protect users from stupid plugin authors who
// did not declare a direct dependency on plexus-utils because the version
// Maven uses is hidden from downstream use. We will also bump up any
// anything below 1.1 to 1.1 as this mimics the behaviour in 2.0.5 where
// plexus-utils 1.1 was being forced into use.
// ----------------------------------------------------------------------------
VersionRange vr = null;
try
{
vr = VersionRange.createFromVersionSpec( "[1.1,)" );
}
catch ( InvalidVersionSpecificationException e )
{
// Won't happen
}
boolean plexusUtilsPresent = false;
for ( Iterator i = dependencyArtifacts.iterator(); i.hasNext(); )
{
Artifact a = (Artifact) i.next();
if ( a.getArtifactId().equals( "plexus-utils" ) &&
vr.containsVersion( new DefaultArtifactVersion( a.getVersion() ) ) )
{
plexusUtilsPresent = true;
break;
}
}
if ( !plexusUtilsPresent )
{
// We will add plexus-utils as every plugin was getting this anyway from Maven itself. We will set the
// version to the latest version we know that works as of the 2.0.6 release. We set the scope to runtime
// as this is what's implicitly happening in 2.0.6.
Set result = new LinkedHashSet();
if ( !dependencyArtifacts.isEmpty() )
{
result.addAll( dependencyArtifacts );
}
result.add( artifactFactory.createArtifact( "org.codehaus.plexus", "plexus-utils", "1.1", Artifact.SCOPE_RUNTIME, "jar" ) );
return result;
}
else
{
return dependencyArtifacts;
}
}
private void resolveCoreArtifacts( List unresolved,
ArtifactRepository localRepository,
List resolutionRepositories )
throws ArtifactResolutionException, ArtifactNotFoundException
{
for ( Iterator it = unresolved.iterator(); it.hasNext(); )
{
Artifact artifact = (Artifact) it.next();
File artifactFile = (File) resolvedCoreArtifactFiles.get( artifact.getId() );
if ( artifactFile == null )
{
String resource =
"/META-INF/maven/" + artifact.getGroupId() + "/" + artifact.getArtifactId() + "/pom.xml";
URL resourceUrl = container.getContainerRealm().getResource( resource );
if ( resourceUrl == null )
{
artifactResolver.resolve( artifact, resolutionRepositories, localRepository );
artifactFile = artifact.getFile();
}
else
{
String artifactPath = resourceUrl.getPath();
if ( artifactPath.startsWith( "file:" ) )
{
artifactPath = artifactPath.substring( "file:".length() );
}
artifactPath = artifactPath.substring( 0, artifactPath.length() - resource.length() );
if ( artifactPath.endsWith( "/" ) )
{
artifactPath = artifactPath.substring( 0, artifactPath.length() - 1 );
}
if ( artifactPath.endsWith( "!" ) )
{
artifactPath = artifactPath.substring( 0, artifactPath.length() - 1 );
}
artifactFile = new File( artifactPath ).getAbsoluteFile();
}
resolvedCoreArtifactFiles.put( artifact.getId(), artifactFile );
}
artifact.setFile( artifactFile );
}
}
private PlexusConfiguration extractMojoConfiguration( PlexusConfiguration mergedConfiguration,
MojoDescriptor mojoDescriptor )
{
Map parameterMap = mojoDescriptor.getParameterMap();
PlexusConfiguration[] mergedChildren = mergedConfiguration.getChildren();
XmlPlexusConfiguration extractedConfiguration = new XmlPlexusConfiguration( "configuration" );
for ( int i = 0; i < mergedChildren.length; i++ )
{
PlexusConfiguration child = mergedChildren[i];
if ( parameterMap.containsKey( child.getName() ) )
{
extractedConfiguration.addChild( copyConfiguration( child ) );
}
else
{
// TODO: I defy anyone to find these messages in the '-X' output! Do we need a new log level?
// ideally, this would be elevated above the true debug output, but below the default INFO level...
// [BP] (2004-07-18): need to understand the context more but would prefer this could be either WARN or
// removed - shouldn't need DEBUG to diagnose a problem most of the time.
getLogger().debug( "*** WARNING: Configuration \'" + child.getName() + "\' is not used in goal \'" +
mojoDescriptor.getFullGoalName() + "; this may indicate a typo... ***" );
}
}
return extractedConfiguration;
}
private void checkRequiredParameters( MojoDescriptor goal,
PlexusConfiguration configuration,
ExpressionEvaluator expressionEvaluator )
throws PluginConfigurationException
{
// TODO: this should be built in to the configurator, as we presently double process the expressions
List parameters = goal.getParameters();
if ( parameters == null )
{
return;
}
List invalidParameters = new ArrayList();
for ( int i = 0; i < parameters.size(); i++ )
{
Parameter parameter = (Parameter) parameters.get( i );
if ( parameter.isRequired() )
{
// the key for the configuration map we're building.
String key = parameter.getName();
Object fieldValue = null;
String expression = null;
PlexusConfiguration value = configuration.getChild( key, false );
try
{
if ( value != null )
{
expression = value.getValue( null );
fieldValue = expressionEvaluator.evaluate( expression );
if ( fieldValue == null )
{
fieldValue = value.getAttribute( "default-value", null );
}
}
if ( ( fieldValue == null ) && StringUtils.isNotEmpty( parameter.getAlias() ) )
{
value = configuration.getChild( parameter.getAlias(), false );
if ( value != null )
{
expression = value.getValue( null );
fieldValue = expressionEvaluator.evaluate( expression );
if ( fieldValue == null )
{
fieldValue = value.getAttribute( "default-value", null );
}
}
}
}
catch ( ExpressionEvaluationException e )
{
throw new PluginConfigurationException( goal.getPluginDescriptor(), e.getMessage(), e );
}
// only mark as invalid if there are no child nodes
if ( ( fieldValue == null ) && ( ( value == null ) || ( value.getChildCount() == 0 ) ) )
{
parameter.setExpression( expression );
invalidParameters.add( parameter );
}
}
}
if ( !invalidParameters.isEmpty() )
{
throw new PluginParameterException( goal, invalidParameters );
}
}
private void validatePomConfiguration( MojoDescriptor goal,
PlexusConfiguration pomConfiguration )
throws PluginConfigurationException
{
List parameters = goal.getParameters();
if ( parameters == null )
{
return;
}
for ( int i = 0; i < parameters.size(); i++ )
{
Parameter parameter = (Parameter) parameters.get( i );
// the key for the configuration map we're building.
String key = parameter.getName();
PlexusConfiguration value = pomConfiguration.getChild( key, false );
if ( ( value == null ) && StringUtils.isNotEmpty( parameter.getAlias() ) )
{
key = parameter.getAlias();
value = pomConfiguration.getChild( key, false );
}
if ( value != null )
{
// Make sure the parameter is either editable/configurable, or else is NOT specified in the POM
if ( !parameter.isEditable() )
{
StringBuffer errorMessage = new StringBuffer()
.append( "ERROR: Cannot override read-only parameter: " );
errorMessage.append( key );
errorMessage.append( " in goal: " ).append( goal.getFullGoalName() );
throw new PluginConfigurationException( goal.getPluginDescriptor(), errorMessage.toString() );
}
String deprecated = parameter.getDeprecated();
if ( StringUtils.isNotEmpty( deprecated ) )
{
getLogger().warn( "DEPRECATED [" + parameter.getName() + "]: " + deprecated );
}
}
}
}
private PlexusConfiguration mergeMojoConfiguration( XmlPlexusConfiguration fromPom,
MojoDescriptor mojoDescriptor )
{
XmlPlexusConfiguration result = new XmlPlexusConfiguration( fromPom.getName() );
result.setValue( fromPom.getValue( null ) );
if ( mojoDescriptor.getParameters() != null )
{
PlexusConfiguration fromMojo = mojoDescriptor.getMojoConfiguration();
for ( Iterator it = mojoDescriptor.getParameters().iterator(); it.hasNext(); )
{
Parameter parameter = (Parameter) it.next();
String paramName = parameter.getName();
String alias = parameter.getAlias();
String implementation = parameter.getImplementation();
PlexusConfiguration pomConfig = fromPom.getChild( paramName );
PlexusConfiguration aliased = null;
if ( alias != null )
{
aliased = fromPom.getChild( alias );
}
PlexusConfiguration mojoConfig = fromMojo.getChild( paramName, false );
// first we'll merge configurations from the aliased and real params.
// TODO: Is this the right thing to do?
if ( aliased != null )
{
if ( pomConfig == null )
{
pomConfig = new XmlPlexusConfiguration( paramName );
}
pomConfig = buildTopDownMergedConfiguration( pomConfig, aliased );
}
PlexusConfiguration toAdd = null;
if ( pomConfig != null )
{
pomConfig = buildTopDownMergedConfiguration( pomConfig, mojoConfig );
if ( StringUtils.isNotEmpty( pomConfig.getValue( null ) ) || ( pomConfig.getChildCount() > 0 ) )
{
toAdd = pomConfig;
}
}
if ( ( toAdd == null ) && ( mojoConfig != null ) )
{
toAdd = copyConfiguration( mojoConfig );
}
if ( toAdd != null )
{
if ( ( implementation != null ) && ( toAdd.getAttribute( "implementation", null ) == null ) )
{
XmlPlexusConfiguration implementationConf = new XmlPlexusConfiguration( paramName );
implementationConf.setAttribute( "implementation", parameter.getImplementation() );
toAdd = buildTopDownMergedConfiguration( toAdd, implementationConf );
}
result.addChild( toAdd );
}
}
}
return result;
}
private XmlPlexusConfiguration buildTopDownMergedConfiguration( PlexusConfiguration dominant,
PlexusConfiguration recessive )
{
XmlPlexusConfiguration result = new XmlPlexusConfiguration( dominant.getName() );
String value = dominant.getValue( null );
if ( StringUtils.isEmpty( value ) && ( recessive != null ) )
{
value = recessive.getValue( null );
}
if ( StringUtils.isNotEmpty( value ) )
{
result.setValue( value );
}
String[] attributeNames = dominant.getAttributeNames();
for ( int i = 0; i < attributeNames.length; i++ )
{
String attributeValue = dominant.getAttribute( attributeNames[i], null );
result.setAttribute( attributeNames[i], attributeValue );
}
if ( recessive != null )
{
attributeNames = recessive.getAttributeNames();
for ( int i = 0; i < attributeNames.length; i++ )
{
String attributeValue = recessive.getAttribute( attributeNames[i], null );
// TODO: recessive seems to be dominant here?
result.setAttribute( attributeNames[i], attributeValue );
}
}
PlexusConfiguration[] children = dominant.getChildren();
for ( int i = 0; i < children.length; i++ )
{
PlexusConfiguration childDom = children[i];
PlexusConfiguration childRec = recessive == null ? null : recessive.getChild( childDom.getName(), false );
if ( childRec != null )
{
result.addChild( buildTopDownMergedConfiguration( childDom, childRec ) );
}
else
{ // FIXME: copy, or use reference?
result.addChild( copyConfiguration( childDom ) );
}
}
return result;
}
public static PlexusConfiguration copyConfiguration( PlexusConfiguration src )
{
// TODO: shouldn't be necessary
XmlPlexusConfiguration dom = new XmlPlexusConfiguration( src.getName() );
dom.setValue( src.getValue( null ) );
String[] attributeNames = src.getAttributeNames();
for ( int i = 0; i < attributeNames.length; i++ )
{
String attributeName = attributeNames[i];
dom.setAttribute( attributeName, src.getAttribute( attributeName, null ) );
}
PlexusConfiguration[] children = src.getChildren();
for ( int i = 0; i < children.length; i++ )
{
dom.addChild( copyConfiguration( children[i] ) );
}
return dom;
}
// ----------------------------------------------------------------------
// Mojo Parameter Handling
// ----------------------------------------------------------------------
private void populatePluginFields( Mojo plugin,
MojoDescriptor mojoDescriptor,
PlexusConfiguration configuration,
PlexusContainer pluginContainer,
ExpressionEvaluator expressionEvaluator )
throws PluginConfigurationException
{
ComponentConfigurator configurator = null;
try
{
String configuratorId = mojoDescriptor.getComponentConfigurator();
// TODO: could the configuration be passed to lookup and the configurator known to plexus via the descriptor
// so that this meethod could entirely be handled by a plexus lookup?
if ( StringUtils.isNotEmpty( configuratorId ) )
{
configurator =
(ComponentConfigurator) pluginContainer.lookup( ComponentConfigurator.ROLE, configuratorId );
}
else
{
configurator = (ComponentConfigurator) pluginContainer.lookup( ComponentConfigurator.ROLE );
}
ConfigurationListener listener = new DebugConfigurationListener( getLogger() );
getLogger().debug( "Configuring mojo '" + mojoDescriptor.getId() + "' -->" );
configurator.configureComponent( plugin, configuration, expressionEvaluator,
pluginContainer.getContainerRealm(), listener );
getLogger().debug( "-- end configuration --" );
}
catch ( ComponentConfigurationException e )
{
throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
"Unable to parse the created DOM for plugin configuration", e );
}
catch ( ComponentLookupException e )
{
throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
"Unable to retrieve component configurator for plugin configuration",
e );
}
catch ( NoClassDefFoundError e )
{
throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
"A required class was missing during mojo configuration: " + e.getMessage(), e );
}
catch ( LinkageError e )
{
if ( getLogger().isFatalErrorEnabled() )
{
getLogger().fatalError(
configurator.getClass().getName() + "#configureComponent(...) caused a linkage error ("
+ e.getClass().getName() + ") and may be out-of-date. Check the realms:" );
ClassRealm pluginRealm = mojoDescriptor.getPluginDescriptor().getClassRealm();
StringBuffer sb = new StringBuffer();
sb.append( "Plugin realm = " + pluginRealm.getId() ).append( '\n' );
for ( int i = 0; i < pluginRealm.getConstituents().length; i++ )
{
sb.append( "urls[" + i + "] = " + pluginRealm.getConstituents()[i] );
if ( i != ( pluginRealm.getConstituents().length - 1 ) )
{
sb.append( '\n' );
}
}
getLogger().fatalError( sb.toString() );
ClassRealm containerRealm = container.getContainerRealm();
sb = new StringBuffer();
sb.append( "Container realm = " + containerRealm.getId() ).append( '\n' );
for ( int i = 0; i < containerRealm.getConstituents().length; i++ )
{
sb.append( "urls[" + i + "] = " + containerRealm.getConstituents()[i] );
if ( i != ( containerRealm.getConstituents().length - 1 ) )
{
sb.append( '\n' );
}
}
getLogger().fatalError( sb.toString() );
}
throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
e.getClass().getName() + ": " + e.getMessage(), e );
}
finally
{
if ( configurator != null )
{
try
{
pluginContainer.release( configurator );
}
catch ( ComponentLifecycleException e )
{
getLogger().debug( "Failed to release plugin container - ignoring." );
}
}
}
}
public static String createPluginParameterRequiredMessage( MojoDescriptor mojo,
Parameter parameter,
String expression )
{
StringBuffer message = new StringBuffer();
message.append( "The '" );
message.append( parameter.getName() );
message.append( "' parameter is required for the execution of the " );
message.append( mojo.getFullGoalName() );
message.append( " mojo and cannot be null." );
if ( expression != null )
{
message.append( " The retrieval expression was: " ).append( expression );
}
return message.toString();
}
// ----------------------------------------------------------------------
// Lifecycle
// ----------------------------------------------------------------------
public void contextualize( Context context )
throws ContextException
{
container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
mojoLogger = new DefaultLog( container.getLoggerManager().getLoggerForComponent( Mojo.ROLE ) );
}
public void initialize()
{
artifactFilter = MavenArtifactFilterManager.createStandardFilter();
}
// ----------------------------------------------------------------------
// Artifact resolution
// ----------------------------------------------------------------------
private void resolveTransitiveDependencies( MavenSession context,
ArtifactResolver artifactResolver,
String scope,
ArtifactFactory artifactFactory,
MavenProject project, boolean isAggregator )
throws ArtifactResolutionException, ArtifactNotFoundException, InvalidDependencyVersionException
{
ArtifactFilter filter = new ScopeArtifactFilter( scope );
// TODO: such a call in MavenMetadataSource too - packaging not really the intention of type
Artifact artifact = artifactFactory.createBuildArtifact( project.getGroupId(), project.getArtifactId(),
project.getVersion(), project.getPackaging() );
// TODO: we don't need to resolve over and over again, as long as we are sure that the parameters are the same
// check this with yourkit as a hot spot.
// Don't recreate if already created - for effeciency, and because clover plugin adds to it
if ( project.getDependencyArtifacts() == null )
{
project.setDependencyArtifacts( project.createArtifacts( artifactFactory, null, null ) );
}
else
{
project.resolveActiveArtifacts();
}
Set resolvedArtifacts;
try
{
ArtifactResolutionResult result = artifactResolver.resolveTransitively( project.getDependencyArtifacts(),
artifact,
project.getManagedVersionMap(),
context.getLocalRepository(),
project.getRemoteArtifactRepositories(),
artifactMetadataSource, filter );
resolvedArtifacts = result.getArtifacts();
}
catch (MultipleArtifactsNotFoundException me)
{
/*only do this if we are an aggregating plugin: MNG-2277
if the dependency doesn't yet exist but is in the reactor, then
all we can do is warn and skip it. A better fix can be inserted into 2.1*/
if (isAggregator && checkMissingArtifactsInReactor( context.getSortedProjects(), me.getMissingArtifacts() ))
{
resolvedArtifacts = new HashSet(me.getResolvedArtifacts());
}
else
{
//we can't find all the artifacts in the reactor so bubble the exception up.
throw me;
}
}
project.setArtifacts( resolvedArtifacts );
}
/**
* This method is checking to see if the artifacts that can't be resolved are all
* part of this reactor. This is done to prevent a chicken or egg scenario with
* fresh projects that have a plugin that is an aggregator and requires dependencies. See
* MNG-2277 for more info.
* @param projects the sibling projects in the reactor
* @param missing the artifacts that can't be found
* @return true if ALL missing artifacts are found in the reactor.
*/
private boolean checkMissingArtifactsInReactor(Collection projects, Collection missing)
{
Collection foundInReactor = new HashSet();
Iterator iter = missing.iterator();
while (iter.hasNext())
{
Artifact mArtifact = (Artifact) iter.next();
Iterator pIter = projects.iterator();
while (pIter.hasNext())
{
MavenProject p = (MavenProject) pIter.next();
if (p.getArtifactId().equals( mArtifact.getArtifactId()) &&
p.getGroupId().equals( mArtifact.getGroupId()) &&
p.getVersion().equals( mArtifact.getVersion()))
{
//TODO: the packaging could be different, but the exception doesn't contain that info
//most likely it would be produced by the project we just found in the reactor since all
//the other info matches. Assume it's ok.
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" );
//found it, move on.
foundInReactor.add( p );
break;
}
}
}
//if all of them have been found, we can continue.
return foundInReactor.size() == missing.size();
}
// ----------------------------------------------------------------------
// Artifact downloading
// ----------------------------------------------------------------------
private void downloadDependencies( MavenProject project,
MavenSession context,
ArtifactResolver artifactResolver )
throws ArtifactResolutionException, ArtifactNotFoundException
{
ArtifactRepository localRepository = context.getLocalRepository();
List remoteArtifactRepositories = project.getRemoteArtifactRepositories();
for ( Iterator it = project.getArtifacts().iterator(); it.hasNext(); )
{
Artifact artifact = (Artifact) it.next();
artifactResolver.resolve( artifact, remoteArtifactRepositories, localRepository );
}
}
public Object getPluginComponent( Plugin plugin,
String role,
String roleHint )
throws PluginManagerException, ComponentLookupException
{
PluginDescriptor pluginDescriptor = pluginCollector.getPluginDescriptor( plugin );
PlexusContainer pluginContainer = getPluginContainer( pluginDescriptor );
return pluginContainer.lookup( role, roleHint );
}
@SuppressWarnings( "unchecked" )
public Map getPluginComponents( Plugin plugin,
String role )
throws ComponentLookupException, PluginManagerException
{
PluginDescriptor pluginDescriptor = pluginCollector.getPluginDescriptor( plugin );
PlexusContainer pluginContainer = getPluginContainer( pluginDescriptor );
Set<String> pluginHints = findChildComponentHints( role, container, pluginContainer );
Map<String, Object> components = new HashMap<String, Object>( pluginHints.size() );
for ( String hint : pluginHints )
{
getLogger().debug( "Looking up plugin component: " + role + " with hint: " + hint );
components.put( hint, pluginContainer.lookup( role, hint ) );
}
return components;
}
/**
* {@inheritDoc}
*/
public PluginDescriptor loadPluginFully( Plugin plugin, MavenProject project, MavenSession session )
throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
PluginVersionNotFoundException
{
PluginDescriptor pd = verifyPlugin( plugin, project, session.getSettings(), session.getLocalRepository() );
PlexusContainer pluginContainer = getPluginContainer( pd );
ensurePluginContainerIsComplete( pd, pluginContainer, project, session );
return pd;
}
/**
* {@inheritDoc}
*/
public PluginDescriptor loadPluginDescriptor( Plugin plugin, MavenProject project, MavenSession session )
throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
PluginVersionNotFoundException
{
return verifyPlugin( plugin, project, session.getSettings(), session.getLocalRepository() );
}
}