o Splitted plugin manager: One general component for any kind of Maven plugin, one specifically tailored for execution of build plugins. The generic plugin manager is meant to be reused by the new Site Plugin, the other plugin manager is private to the core.

git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@805826 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Benjamin Bentmann 2009-08-19 14:52:04 +00:00
parent 374d818a0c
commit fd54fd1f07
11 changed files with 1035 additions and 602 deletions

View File

@ -19,6 +19,8 @@ package org.apache.maven.classrealm;
* under the License.
*/
import java.util.List;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
@ -42,11 +44,21 @@ public interface ClassRealmManager
ClassRealm createProjectRealm( Model model );
/**
* Creates a new class realm for the specified plugin.
* Creates a new class realm for the specified build plugin.
*
* @param plugin The plugin for which to create a realm, must not be {@code null}.
* @param plugin The build plugin for which to create a realm, must not be {@code null}.
* @return The new plugin realm, never {@code null}.
*/
ClassRealm createPluginRealm( Plugin plugin );
/**
* Creates a new class realm for the specified plugin.
*
* @param plugin The plugin for which to create a realm, must not be {@code null}.
* @param parent The parent realm for the new realm, may be {@code null} to use the Maven core realm.
* @param imports The packages/types to import from the parent realm, may be {@code null}.
* @return The new plugin realm, never {@code null}.
*/
ClassRealm createPluginRealm( Plugin plugin, ClassLoader parent, List<String> imports );
}

View File

@ -59,7 +59,15 @@ public class DefaultClassRealmManager
return ( (MutablePlexusContainer) container ).getClassWorld();
}
private ClassRealm createRealm( String baseRealmId )
/**
* Creates a new class realm with the specified parent and imports.
*
* @param baseRealmId The base id to use for the new realm, must not be {@code null}.
* @param parent The parent realm for the new realm, may be {@code null} to use the Maven core realm.
* @param imports The packages/types to import from the parent realm, may be {@code null}.
* @return The created class realm, never {@code null}.
*/
private ClassRealm createRealm( String baseRealmId, ClassLoader parent, List<String> imports )
{
ClassWorld world = getClassWorld();
@ -90,11 +98,27 @@ public class DefaultClassRealmManager
}
}
classRealm.setParentRealm( container.getContainerRealm() );
if ( parent != null )
{
classRealm.setParentClassLoader( parent );
}
else
{
classRealm.setParentRealm( container.getContainerRealm() );
importMavenApi( classRealm );
}
importXpp3Dom( classRealm );
importMavenApi( classRealm );
if ( imports != null && !imports.isEmpty() )
{
ClassLoader importedRealm = classRealm.getParentClassLoader();
for ( String imp : imports )
{
classRealm.importFrom( importedRealm, imp );
}
}
for ( ClassRealmManagerDelegate delegate : getDelegates() )
{
@ -162,7 +186,7 @@ public class DefaultClassRealmManager
throw new IllegalArgumentException( "model missing" );
}
return createRealm( getKey( model ) );
return createRealm( getKey( model ), null, null );
}
private String getKey( Model model )
@ -177,7 +201,17 @@ public class DefaultClassRealmManager
throw new IllegalArgumentException( "plugin missing" );
}
return createRealm( getKey( plugin ) );
return createRealm( getKey( plugin ), null, null );
}
public ClassRealm createPluginRealm( Plugin plugin, ClassLoader parent, List<String> imports )
{
if ( plugin == null )
{
throw new IllegalArgumentException( "plugin missing" );
}
return createRealm( getKey( plugin ), parent, imports );
}
private String getKey( Plugin plugin )

View File

@ -0,0 +1,189 @@
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 java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.RepositoryRequest;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.repository.ComponentDescriptor;
/**
* Caches raw plugin descriptors. A raw plugin descriptor is a descriptor that has just been extracted from the plugin
* artifact and does not contain any runtime specific data. The cache must not be used for descriptors that hold runtime
* data like the plugin realm. <strong>Warning:</strong> This is an internal utility interface that is only public for
* technical reasons, it is not part of the public API. In particular, this interface can be changed or deleted without
* prior notice.
*
* @author Benjamin Bentmann
*/
@Component( role = PluginDescriptorCache.class )
public class DefaultPluginDescriptorCache
implements PluginDescriptorCache
{
private Map<Key, PluginDescriptor> descriptors = new HashMap<Key, PluginDescriptor>( 128 );
public void flush()
{
descriptors.clear();
}
public Key createKey( Plugin plugin, RepositoryRequest repositoryRequest )
{
return new CacheKey( plugin, repositoryRequest );
}
public void put( Key cacheKey, PluginDescriptor pluginDescriptor )
{
descriptors.put( cacheKey, clone( pluginDescriptor ) );
}
public PluginDescriptor get( Key cacheKey )
{
return clone( descriptors.get( cacheKey ) );
}
private static PluginDescriptor clone( PluginDescriptor original )
{
PluginDescriptor clone = null;
if ( original != null )
{
clone = new PluginDescriptor();
clone.setGroupId( original.getGroupId() );
clone.setArtifactId( original.getArtifactId() );
clone.setVersion( original.getVersion() );
clone.setGoalPrefix( original.getGoalPrefix() );
clone.setInheritedByDefault( original.isInheritedByDefault() );
clone.setName( original.getName() );
clone.setDescription( original.getDescription() );
clone.setPluginArtifact( ArtifactUtils.copyArtifactSafe( original.getPluginArtifact() ) );
clone.setComponents( clone( original.getMojos(), clone ) );
clone.setId( original.getId() );
clone.setIsolatedRealm( original.isIsolatedRealm() );
clone.setSource( original.getSource() );
}
return clone;
}
private static List<ComponentDescriptor<?>> clone( List<MojoDescriptor> mojos, PluginDescriptor pluginDescriptor )
{
List<ComponentDescriptor<?>> clones = null;
if ( mojos != null )
{
clones = new ArrayList<ComponentDescriptor<?>>( mojos.size() );
for ( MojoDescriptor mojo : mojos )
{
MojoDescriptor clone = mojo.clone();
clone.setPluginDescriptor( pluginDescriptor );
clones.add( clone );
}
}
return clones;
}
private static <T> List<T> clone( List<T> original )
{
return ( original != null ) ? new ArrayList<T>( original ) : null;
}
private static final class CacheKey
implements Key
{
private final String groupId;
private final String artifactId;
private final String version;
private final List<ArtifactRepository> repositories;
private final int hashCode;
public CacheKey( Plugin plugin, RepositoryRequest repositoryRequest )
{
groupId = plugin.getGroupId();
artifactId = plugin.getArtifactId();
version = plugin.getVersion();
repositories = new ArrayList<ArtifactRepository>( repositoryRequest.getRemoteRepositories().size() + 1 );
repositories.add( repositoryRequest.getLocalRepository() );
repositories.addAll( repositoryRequest.getRemoteRepositories() );
int hash = 17;
hash = hash * 31 + groupId.hashCode();
hash = hash * 31 + artifactId.hashCode();
hash = hash * 31 + version.hashCode();
hash = hash * 31 + repositories.hashCode();
this.hashCode = hash;
}
@Override
public int hashCode()
{
return hashCode;
}
@Override
public boolean equals( Object obj )
{
if ( this == obj )
{
return true;
}
if ( !( obj instanceof CacheKey ) )
{
return false;
}
CacheKey that = (CacheKey) obj;
return this.artifactId.equals( that.artifactId ) && this.groupId.equals( that.groupId )
&& this.version.equals( that.version ) && this.repositories.equals( that.repositories );
}
@Override
public String toString()
{
return groupId + ':' + artifactId + ':' + version;
}
}
}

View File

@ -15,67 +15,25 @@ package org.apache.maven.plugin;
* the License.
*/
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import org.apache.maven.ArtifactFilterManager;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.DefaultRepositoryRequest;
import org.apache.maven.artifact.repository.RepositoryRequest;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ResolutionErrorHandler;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.classrealm.ClassRealmManager;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Plugin;
import org.apache.maven.monitor.logging.DefaultLog;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
import org.apache.maven.project.DuplicateArtifactAttachmentException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.component.composition.CycleDetectedInComponentGraphException;
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.ExpressionEvaluator;
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.PlexusConfigurationException;
import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.InterpolationFilterReader;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.XmlStreamReader;
import org.codehaus.plexus.util.xml.Xpp3Dom;
// TODO: the antrun plugin has its own configurator, the only plugin that does. might need to think about how that works
// TODO: remove the coreArtifactFilterManager
@ -84,27 +42,16 @@ import org.codehaus.plexus.util.xml.Xpp3Dom;
public class DefaultPluginManager
implements PluginManager
{
@Requirement
private Logger logger;
@Requirement
protected PlexusContainer container;
@Requirement
private ClassRealmManager classRealmManager;
@Requirement
protected ArtifactFilterManager coreArtifactFilterManager;
@Requirement
protected RepositorySystem repositorySystem;
@Requirement
private ResolutionErrorHandler resolutionErrorHandler;
private PlexusContainer container;
@Requirement
private PluginCache pluginCache;
@Requirement
private MavenPluginManager mavenPluginManager;
/**
*
* @param plugin
@ -120,190 +67,7 @@ public class DefaultPluginManager
public synchronized PluginDescriptor loadPlugin( Plugin plugin, RepositoryRequest repositoryRequest )
throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, CycleDetectedInPluginGraphException, InvalidPluginDescriptorException
{
PluginDescriptor pluginDescriptor =
pluginCache.getPluginDescriptor( plugin, repositoryRequest.getLocalRepository(),
repositoryRequest.getRemoteRepositories() );
if ( pluginDescriptor != null )
{
return pluginDescriptor;
}
Artifact pluginArtifact = repositorySystem.createPluginArtifact( plugin );
ArtifactResolutionRequest request = new ArtifactResolutionRequest( repositoryRequest )
.setArtifact( pluginArtifact )
.setResolveTransitively( false );
// FIXME setTransferListener
ArtifactResolutionResult result = repositorySystem.resolve( request );
try
{
resolutionErrorHandler.throwErrors( request, result );
}
catch ( ArtifactResolutionException e )
{
throw new PluginResolutionException( plugin, e );
}
try
{
if ( pluginArtifact.getFile().isFile() )
{
JarFile pluginJar = new JarFile( pluginArtifact.getFile() );
try
{
ZipEntry pluginDescriptorEntry = pluginJar.getEntry( getComponentDescriptorLocation() );
if ( pluginDescriptorEntry != null )
{
InputStream is = pluginJar.getInputStream( pluginDescriptorEntry );
pluginDescriptor = parsebuildPluginDescriptor( is );
}
}
finally
{
pluginJar.close();
}
}
else
{
File pluginXml = new File( pluginArtifact.getFile(), getComponentDescriptorLocation() );
if ( pluginXml.canRead() )
{
InputStream is = new BufferedInputStream( new FileInputStream( pluginXml ) );
try
{
pluginDescriptor = parsebuildPluginDescriptor( is );
}
finally
{
IOUtil.close( is );
}
}
}
String pluginKey = constructPluginKey( plugin );
if ( pluginDescriptor == null )
{
throw new InvalidPluginDescriptorException( "Invalid or missing Plugin Descriptor for " + pluginKey );
}
// Check the internal consistent of a plugin descriptor when it is discovered. Most of the time the plugin descriptor is generated
// by the maven-plugin-plugin, but if you happened to have created one by hand and it's incorrect this validator will report
// the problem to the user.
//
MavenPluginValidator validator = new MavenPluginValidator( pluginArtifact );
validator.validate( pluginDescriptor );
if ( validator.hasErrors() )
{
throw new InvalidPluginDescriptorException( "Invalid Plugin Descriptor for " + pluginKey, validator.getErrors() );
}
pluginDescriptor.setPlugin( plugin );
pluginDescriptor.setPluginArtifact( pluginArtifact );
pluginCache.putPluginDescriptor( plugin, repositoryRequest.getLocalRepository(),
repositoryRequest.getRemoteRepositories(), pluginDescriptor );
return pluginDescriptor;
}
catch ( IOException e )
{
throw new PluginDescriptorParsingException( plugin, e );
}
catch ( PlexusConfigurationException e )
{
throw new PluginDescriptorParsingException( plugin, e );
}
}
// TODO: This is only public for reuse by the 3.x compatible maven-plugin-testing-harness ...
public PluginDescriptor parsebuildPluginDescriptor( InputStream is )
throws IOException, PlexusConfigurationException
{
PluginDescriptor pluginDescriptor;
XmlStreamReader reader = ReaderFactory.newXmlReader( is );
InterpolationFilterReader interpolationFilterReader = new InterpolationFilterReader( new BufferedReader( reader ), container.getContext().getContextData() );
pluginDescriptor = builder.build( interpolationFilterReader );
return pluginDescriptor;
}
// TODO: Turn this into a component so it can be tested.
//
/**
* Gets all artifacts required for the class realm of the specified plugin. An artifact in the result list that has
* no file set is meant to be excluded from the plugin realm in favor of the equivalent library from the current
* core distro.
*/
List<Artifact> getPluginArtifacts( Artifact pluginArtifact, Plugin pluginAsSpecifiedInPom, RepositoryRequest repositoryRequest )
throws ArtifactNotFoundException, ArtifactResolutionException
{
ArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME_PLUS_SYSTEM );
Set<Artifact> dependenciesToResolveForPlugin = new LinkedHashSet<Artifact>();
// The case where we have a plugin that can host multiple versions of a particular tool. Say the
// Antlr plugin which has many versions and you may want the plugin to execute with version 2.7.1 of
// Antlr versus 2.7.2. In this case the project itself would specify dependencies within the plugin
// element.
// These dependencies might called override dependencies. We want anything in this set of override
// any of the resolved dependencies of the plugin artifact.
// We would almost always want the everything to be resolved from the root but we have this special case
// of overrides from the project itself which confused the interface.
for( Dependency dependencySpecifiedInProject : pluginAsSpecifiedInPom.getDependencies() )
{
// Right now if you add override dependencies they will not be operated on by the metadata source. The metadata source first grabs the plugins
// defined dependencies and then the result is merged with the overrides. The overrides don't pass through the metadata source which is where the
// Artifact.setFile( file ) method is called. We should eventually take care of this in the resolver.
Artifact a = repositorySystem.createDependencyArtifact( dependencySpecifiedInProject );
dependenciesToResolveForPlugin.add( a );
}
ArtifactResolutionRequest request = new ArtifactResolutionRequest( repositoryRequest )
.setArtifact( pluginArtifact )
// So this in fact are overrides ...
.setArtifactDependencies( dependenciesToResolveForPlugin )
.setFilter( filter )
.setResolveRoot( true )
.setResolveTransitively( true );
// FIXME setTransferListener
ArtifactResolutionResult result = repositorySystem.collect( request );
resolutionErrorHandler.throwErrors( request, result );
List<Artifact> pluginArtifacts = new ArrayList<Artifact>( result.getArtifacts() );
request.setResolveRoot( true ).setResolveTransitively( false ).setArtifactDependencies( null );
filter = coreArtifactFilterManager.getCoreArtifactFilter();
for ( Artifact artifact : pluginArtifacts )
{
if ( filter.include( artifact ) )
{
result = repositorySystem.resolve( request.setArtifact( artifact ) );
resolutionErrorHandler.throwErrors( request, result );
}
else
{
artifact.setFile( null );
artifact.setResolved( false );
}
}
return pluginArtifacts;
return mavenPluginManager.getPluginDescriptor( plugin, repositoryRequest );
}
// ----------------------------------------------------------------------
@ -317,8 +81,6 @@ public class DefaultPluginManager
MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
String goalName = mojoDescriptor.getFullGoalName();
Mojo mojo = null;
ClassRealm pluginRealm = getPluginRealm( session, mojoDescriptor.getPluginDescriptor() );
@ -327,7 +89,7 @@ public class DefaultPluginManager
try
{
mojo = getConfiguredMojo( session, project, mojoExecution, pluginRealm );
mojo = mavenPluginManager.getConfiguredMojo( Mojo.class, session, mojoExecution );
Thread.currentThread().setContextClassLoader( pluginRealm );
@ -355,23 +117,7 @@ public class DefaultPluginManager
}
finally
{
if ( mojo != null )
{
try
{
container.release( mojo );
}
catch ( ComponentLifecycleException e )
{
String goalExecId = goalName;
if ( mojoExecution.getExecutionId() != null )
{
goalExecId += " {execution: " + mojoExecution.getExecutionId() + "}";
}
logger.debug( "Error releasing mojo for: " + goalExecId, e );
}
}
mavenPluginManager.releaseMojo( mojo, mojoExecution );
if ( oldLookupRealm != null )
{
@ -385,6 +131,7 @@ public class DefaultPluginManager
/**
* TODO pluginDescriptor classRealm and artifacts are set as a side effect of this
* call, which is not nice.
* @throws ArtifactResolutionException
*/
public synchronized ClassRealm getPluginRealm( MavenSession session, PluginDescriptor pluginDescriptor )
throws PluginManagerException
@ -396,7 +143,7 @@ public class DefaultPluginManager
}
Plugin plugin = pluginDescriptor.getPlugin();
ArtifactRepository localRepository = session.getLocalRepository();
List<ArtifactRepository> remoteRepositories = session.getCurrentProject().getPluginArtifactRepositories();
@ -406,342 +153,30 @@ public class DefaultPluginManager
{
pluginDescriptor.setClassRealm( cacheRecord.realm );
pluginDescriptor.setArtifacts( new ArrayList<Artifact>( cacheRecord.artifacts ) );
return pluginRealm;
}
pluginRealm = createPluginRealm( plugin );
Artifact pluginArtifact = pluginDescriptor.getPluginArtifact();
List<Artifact> pluginArtifacts;
try
else
{
RepositoryRequest request = new DefaultRepositoryRequest();
request.setLocalRepository( localRepository );
request.setRemoteRepositories( remoteRepositories );
request.setCache( session.getRepositoryCache() );
request.setOffline( session.isOffline() );
pluginArtifacts = getPluginArtifacts( pluginArtifact, plugin, request );
}
catch ( ArtifactNotFoundException e )
{
throw new IllegalStateException( e ); // XXX
}
catch ( ArtifactResolutionException e )
{
throw new IllegalStateException( e ); // XXX
}
if ( logger.isDebugEnabled() )
{
logger.debug( "Populating plugin realm for " + constructPluginKey( plugin ) );
}
List<Artifact> exposedPluginArtifacts = new ArrayList<Artifact>();
for ( Artifact a : pluginArtifacts )
{
if ( a.getFile() != null )
{
if ( logger.isDebugEnabled() )
{
logger.debug( " Included: " + a.getId() );
}
exposedPluginArtifacts.add( a );
try
{
pluginRealm.addURL( a.getFile().toURI().toURL() );
}
catch ( MalformedURLException e )
{
// Not going to happen
}
}
else
{
if ( logger.isDebugEnabled() )
{
logger.debug( " Excluded: " + a.getId() );
}
}
}
pluginDescriptor.setClassRealm( pluginRealm );
pluginDescriptor.setArtifacts( exposedPluginArtifacts );
try
{
for ( ComponentDescriptor componentDescriptor : pluginDescriptor.getComponents() )
{
componentDescriptor.setRealm( pluginRealm );
container.addComponentDescriptor( componentDescriptor );
}
container.discoverComponents( pluginRealm );
}
catch ( PlexusConfigurationException e )
{
throw new PluginManagerException( plugin, e.getMessage(), e );
}
catch ( CycleDetectedInComponentGraphException e )
{
throw new PluginManagerException( plugin, e.getMessage(), e );
}
pluginCache.put( plugin, localRepository, remoteRepositories, pluginRealm, exposedPluginArtifacts );
return pluginRealm;
}
/**
* Creates ClassRealm with unique id for the given plugin
*/
private ClassRealm createPluginRealm( Plugin plugin )
{
return classRealmManager.createPluginRealm( plugin );
}
private Mojo getConfiguredMojo( MavenSession session, MavenProject project, MojoExecution mojoExecution, ClassRealm pluginRealm )
throws PluginConfigurationException, PluginManagerException
{
MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
// We are forcing the use of the plugin realm for all lookups that might occur during
// the lifecycle that is part of the lookup. Here we are specifically trying to keep
// lookups that occur in contextualize calls in line with the right realm.
ClassRealm oldLookupRealm = container.setLookupRealm( pluginRealm );
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader( pluginRealm );
container.setLookupRealm( pluginRealm );
try
{
Mojo mojo;
try
{
mojo = container.lookup( Mojo.class, mojoDescriptor.getRoleHint() );
mavenPluginManager.setupPluginRealm( pluginDescriptor, session, null, null );
}
catch ( ComponentLookupException e )
catch ( PluginResolutionException e )
{
Throwable cause = e.getCause();
while ( cause != null && !( cause instanceof LinkageError )
&& !( cause instanceof ClassNotFoundException ) )
{
cause = cause.getCause();
}
throw new PluginManagerException( plugin, e.getMessage(), e );
}
if ( ( cause instanceof NoClassDefFoundError ) || ( cause instanceof ClassNotFoundException ) )
{
throw new PluginContainerException( mojoDescriptor, pluginRealm, "Unable to load the mojo '"
+ mojoDescriptor.getGoal() + "' in the plugin '" + pluginDescriptor.getId()
+ "'. A required class is missing: " + cause.getMessage(), e );
}
throw new PluginContainerException( mojoDescriptor, pluginRealm, "Unable to find the mojo '"
+ mojoDescriptor.getGoal() + "' (or one of its required components) in the plugin '"
+ pluginDescriptor.getId() + "'", e );
}
if ( mojo instanceof ContextEnabled )
{
//TODO: find somewhere better to put the plugin context.
Map<String, Object> pluginContext = session.getPluginContext( pluginDescriptor, project );
if ( pluginContext != null )
{
pluginContext.put( "project", project );
pluginContext.put( "pluginDescriptor", pluginDescriptor );
( (ContextEnabled) mojo ).setPluginContext( pluginContext );
}
}
mojo.setLog( new DefaultLog( logger ) );
Xpp3Dom dom = mojoExecution.getConfiguration();
PlexusConfiguration pomConfiguration;
if ( dom == null )
{
pomConfiguration = new XmlPlexusConfiguration( "configuration" );
}
else
{
pomConfiguration = new XmlPlexusConfiguration( dom );
}
ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator( session, mojoExecution );
populatePluginFields( mojo, mojoDescriptor, pluginRealm, pomConfiguration, expressionEvaluator );
return mojo;
}
finally
{
Thread.currentThread().setContextClassLoader( oldClassLoader );
container.setLookupRealm( oldLookupRealm );
pluginCache.put( plugin, localRepository, remoteRepositories, pluginDescriptor.getClassRealm(),
pluginDescriptor.getArtifacts() );
}
return pluginDescriptor.getClassRealm();
}
// ----------------------------------------------------------------------
// Mojo Parameter Handling
// ----------------------------------------------------------------------
private void populatePluginFields( Mojo mojo, MojoDescriptor mojoDescriptor, ClassRealm realm, PlexusConfiguration configuration, 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 = container.lookup( ComponentConfigurator.class, configuratorId );
}
else
{
configurator = container.lookup( ComponentConfigurator.class, "basic" );
}
ConfigurationListener listener = new DebugConfigurationListener( logger );
logger.debug( "Configuring mojo '" + mojoDescriptor.getId() + "' with " + ( configuratorId == null ? "basic" : configuratorId ) + " configurator -->" );
// This needs to be able to use methods
configurator.configureComponent( mojo, configuration, expressionEvaluator, realm, listener );
logger.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 ( logger.isFatalErrorEnabled() )
{
logger.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();
StringBuilder sb = new StringBuilder();
sb.append( "Plugin realm = " + pluginRealm.getId() ).append( '\n' );
for ( int i = 0; i < pluginRealm.getURLs().length; i++ )
{
sb.append( "urls[" + i + "] = " + pluginRealm.getURLs()[i] );
if ( i != ( pluginRealm.getURLs().length - 1 ) )
{
sb.append( '\n' );
}
}
logger.fatalError( sb.toString() );
ClassRealm containerRealm = container.getContainerRealm();
sb = new StringBuilder();
sb.append( "Container realm = " + containerRealm.getId() ).append( '\n' );
for ( int i = 0; i < containerRealm.getURLs().length; i++ )
{
sb.append( "urls[" + i + "] = " + containerRealm.getURLs()[i] );
if ( i != ( containerRealm.getURLs().length - 1 ) )
{
sb.append( '\n' );
}
}
logger.fatalError( sb.toString() );
}
throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), e.getClass().getName() + ": " + e.getMessage(), new ComponentConfigurationException( e ) );
}
finally
{
if ( configurator != null )
{
try
{
container.release( configurator );
}
catch ( ComponentLifecycleException e )
{
logger.debug( "Failed to release plugin container - ignoring." );
}
}
}
}
public MojoDescriptor getMojoDescriptor( String groupId, String artifactId, String version, String goal, RepositoryRequest repositoryRequest )
throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, CycleDetectedInPluginGraphException, MojoNotFoundException, InvalidPluginDescriptorException
{
Plugin plugin = new Plugin();
plugin.setGroupId( groupId );
plugin.setArtifactId( artifactId );
plugin.setVersion( version );
return getMojoDescriptor( plugin, goal, repositoryRequest );
}
public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, RepositoryRequest repositoryRequest )
throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, CycleDetectedInPluginGraphException, MojoNotFoundException, InvalidPluginDescriptorException
throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
CycleDetectedInPluginGraphException, MojoNotFoundException, InvalidPluginDescriptorException
{
PluginDescriptor pluginDescriptor = loadPlugin( plugin, repositoryRequest );
MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( goal );
if ( mojoDescriptor == null )
{
throw new MojoNotFoundException( goal, pluginDescriptor );
}
return mojoDescriptor;
return mavenPluginManager.getMojoDescriptor( plugin, goal, repositoryRequest );
}
// ----------------------------------------------------------------------
// Component Discovery
// ----------------------------------------------------------------------
private PluginDescriptorBuilder builder = new PluginDescriptorBuilder();
public String getComponentDescriptorLocation()
{
return "META-INF/maven/plugin.xml";
}
// ----------------------------------------------------------------------
// Component Discovery Listener
// ----------------------------------------------------------------------
public String constructPluginKey( Plugin plugin )
{
String version = ArtifactUtils.toSnapshotVersion( plugin.getVersion() );
return plugin.getGroupId() + ":" + plugin.getArtifactId() + ":" + version;
}
public String constructPluginKey( PluginDescriptor pluginDescriptor )
{
String version = ArtifactUtils.toSnapshotVersion( pluginDescriptor.getVersion() );
return pluginDescriptor.getGroupId() + ":" + pluginDescriptor.getArtifactId() + ":" + version;
}
}

View File

@ -0,0 +1,56 @@
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 java.util.List;
import org.apache.maven.artifact.repository.RepositoryRequest;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
/**
* Provides basic services to manage Maven plugins and their mojos. This component is kept general in its design such
* that the plugins/mojos can be used in arbitrary contexts. In particular, the mojos can be used for ordinary build
* plugins as well as special purpose plugins like reports.
*
* @author Benjamin Bentmann
*/
public interface MavenPluginManager
{
PluginDescriptor getPluginDescriptor( Plugin plugin, RepositoryRequest repositoryRequest )
throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException;
MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, RepositoryRequest repositoryRequest )
throws MojoNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
InvalidPluginDescriptorException;
void setupPluginRealm( PluginDescriptor pluginDescriptor, MavenSession session, ClassLoader parent,
List<String> imports )
throws PluginResolutionException, PluginManagerException;
<T> T getConfiguredMojo( Class<T> mojoInterface, MavenSession session, MojoExecution mojoExecution )
throws PluginConfigurationException, PluginContainerException;
void releaseMojo( Object mojo, MojoExecution mojoExecution );
}

View File

@ -0,0 +1,54 @@
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 org.apache.maven.artifact.repository.RepositoryRequest;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
/**
* Caches raw plugin descriptors. A raw plugin descriptor is a descriptor that has just been extracted from the plugin
* artifact and does not contain any runtime specific data. The cache must not be used for descriptors that hold runtime
* data like the plugin realm. <strong>Warning:</strong> This is an internal utility interface that is only public for
* technical reasons, it is not part of the public API. In particular, this interface can be changed or deleted without
* prior notice.
*
* @author Benjamin Bentmann
*/
public interface PluginDescriptorCache
{
/**
* A cache key.
*/
interface Key
{
// marker interface for cache keys
}
Key createKey( Plugin plugin, RepositoryRequest repositoryRequest );
void put( Key cacheKey, PluginDescriptor pluginDescriptor );
PluginDescriptor get( Key cacheKey );
void flush();
}

View File

@ -31,10 +31,6 @@ public interface PluginManager
PluginDescriptor loadPlugin( Plugin plugin, RepositoryRequest repositoryRequest )
throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, CycleDetectedInPluginGraphException, InvalidPluginDescriptorException;
// igorf: Way too many declared exceptions!
MojoDescriptor getMojoDescriptor( String groupId, String artifactId, String version, String goal, RepositoryRequest repositoryRequest )
throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, CycleDetectedInPluginGraphException, MojoNotFoundException, InvalidPluginDescriptorException;
// igorf: Way too many declared exceptions!
MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, RepositoryRequest repositoryRequest )
throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, CycleDetectedInPluginGraphException, MojoNotFoundException, InvalidPluginDescriptorException;

View File

@ -59,7 +59,7 @@ public class PluginManagerException
pluginVersion = plugin.getVersion();
}
protected PluginManagerException( Plugin plugin, String message, Throwable cause )
public PluginManagerException( Plugin plugin, String message, Throwable cause )
{
super( message, cause );

View File

@ -20,7 +20,6 @@ package org.apache.maven.plugin;
*/
import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.model.Plugin;
@ -37,7 +36,8 @@ public class PluginResolutionException
public PluginResolutionException( Plugin plugin, ArtifactResolutionException e )
{
super( "Plugin could not be resolved: " + e.getMessage(), e.getGroupId(), e.getArtifactId(), e.getVersion(), "maven-plugin", null, e.getRemoteRepositories(), null, e.getCause() );
super( "Plugin or one of its dependencies could not be resolved: " + e.getMessage(), e.getGroupId(),
e.getArtifactId(), e.getVersion(), e.getType(), null, e.getRemoteRepositories(), null, e.getCause() );
this.plugin = plugin;
}

View File

@ -0,0 +1,655 @@
package org.apache.maven.plugin.internal;
/*
* 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 java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import org.apache.maven.ArtifactFilterManager;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.DefaultRepositoryRequest;
import org.apache.maven.artifact.repository.RepositoryRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ResolutionErrorHandler;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.classrealm.ClassRealmManager;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Plugin;
import org.apache.maven.monitor.logging.DefaultLog;
import org.apache.maven.plugin.ContextEnabled;
import org.apache.maven.plugin.DebugConfigurationListener;
import org.apache.maven.plugin.InvalidPluginDescriptorException;
import org.apache.maven.plugin.MavenPluginManager;
import org.apache.maven.plugin.MavenPluginValidator;
import org.apache.maven.plugin.Mojo;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoNotFoundException;
import org.apache.maven.plugin.PluginConfigurationException;
import org.apache.maven.plugin.PluginContainerException;
import org.apache.maven.plugin.PluginDescriptorCache;
import org.apache.maven.plugin.PluginDescriptorParsingException;
import org.apache.maven.plugin.PluginManagerException;
import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
import org.apache.maven.plugin.PluginResolutionException;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.component.composition.CycleDetectedInComponentGraphException;
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.ExpressionEvaluator;
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.PlexusConfigurationException;
import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.InterpolationFilterReader;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.XmlStreamReader;
import org.codehaus.plexus.util.xml.Xpp3Dom;
/**
* Provides basic services to manage Maven plugins and their mojos. This component is kept general in its design such
* that the plugins/mojos can be used in arbitrary contexts. In particular, the mojos can be used for ordinary build
* plugins as well as special purpose plugins like reports.
*
* @author Benjamin Bentmann
*/
@Component( role = MavenPluginManager.class )
public class DefaultMavenPluginManager
implements MavenPluginManager
{
@Requirement
private Logger logger;
@Requirement
private PlexusContainer container;
@Requirement
private ClassRealmManager classRealmManager;
@Requirement
protected RepositorySystem repositorySystem;
@Requirement
private ResolutionErrorHandler resolutionErrorHandler;
@Requirement
private ArtifactFilterManager artifactFilterManager;
@Requirement
private PluginDescriptorCache pluginDescriptorCache;
private PluginDescriptorBuilder builder = new PluginDescriptorBuilder();
public synchronized PluginDescriptor getPluginDescriptor( Plugin plugin, RepositoryRequest repositoryRequest )
throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException
{
PluginDescriptorCache.Key cacheKey = pluginDescriptorCache.createKey( plugin, repositoryRequest );
PluginDescriptor pluginDescriptor = pluginDescriptorCache.get( cacheKey );
if ( pluginDescriptor == null )
{
Artifact pluginArtifact = resolvePluginArtifact( plugin, repositoryRequest );
pluginDescriptor = extractPluginDescriptor( pluginArtifact, plugin );
pluginDescriptorCache.put( cacheKey, pluginDescriptor );
}
pluginDescriptor.setPlugin( plugin );
return pluginDescriptor;
}
private Artifact resolvePluginArtifact( Plugin plugin, RepositoryRequest repositoryRequest )
throws PluginResolutionException
{
Artifact pluginArtifact = repositorySystem.createPluginArtifact( plugin );
ArtifactResolutionRequest request = new ArtifactResolutionRequest( repositoryRequest );
request.setArtifact( pluginArtifact );
request.setResolveTransitively( false );
ArtifactResolutionResult result = repositorySystem.resolve( request );
try
{
resolutionErrorHandler.throwErrors( request, result );
}
catch ( ArtifactResolutionException e )
{
throw new PluginResolutionException( plugin, e );
}
return pluginArtifact;
}
private PluginDescriptor extractPluginDescriptor( Artifact pluginArtifact, Plugin plugin )
throws PluginDescriptorParsingException, InvalidPluginDescriptorException
{
PluginDescriptor pluginDescriptor = null;
File pluginFile = pluginArtifact.getFile();
try
{
if ( pluginFile.isFile() )
{
JarFile pluginJar = new JarFile( pluginFile, false );
try
{
ZipEntry pluginDescriptorEntry = pluginJar.getEntry( getPluginDescriptorLocation() );
if ( pluginDescriptorEntry != null )
{
InputStream is = pluginJar.getInputStream( pluginDescriptorEntry );
pluginDescriptor = parsePluginDescriptor( is, plugin );
}
}
finally
{
pluginJar.close();
}
}
else
{
File pluginXml = new File( pluginFile, getPluginDescriptorLocation() );
if ( pluginXml.canRead() )
{
InputStream is = new BufferedInputStream( new FileInputStream( pluginXml ) );
try
{
pluginDescriptor = parsePluginDescriptor( is, plugin );
}
finally
{
IOUtil.close( is );
}
}
}
}
catch ( IOException e )
{
throw new PluginDescriptorParsingException( plugin, e );
}
if ( pluginDescriptor == null )
{
throw new InvalidPluginDescriptorException( "Missing plugin descriptor for " + plugin.getId() );
}
MavenPluginValidator validator = new MavenPluginValidator( pluginArtifact );
validator.validate( pluginDescriptor );
if ( validator.hasErrors() )
{
throw new InvalidPluginDescriptorException( "Invalid plugin descriptor for " + plugin.getId(),
validator.getErrors() );
}
pluginDescriptor.setPluginArtifact( pluginArtifact );
return pluginDescriptor;
}
private String getPluginDescriptorLocation()
{
return "META-INF/maven/plugin.xml";
}
private PluginDescriptor parsePluginDescriptor( InputStream is, Plugin plugin )
throws PluginDescriptorParsingException
{
try
{
XmlStreamReader reader = ReaderFactory.newXmlReader( is );
InterpolationFilterReader interpolationFilterReader =
new InterpolationFilterReader( new BufferedReader( reader ), container.getContext().getContextData() );
PluginDescriptor pluginDescriptor = builder.build( interpolationFilterReader );
return pluginDescriptor;
}
catch ( IOException e )
{
throw new PluginDescriptorParsingException( plugin, e );
}
catch ( PlexusConfigurationException e )
{
throw new PluginDescriptorParsingException( plugin, e );
}
}
public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, RepositoryRequest repositoryRequest )
throws MojoNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
InvalidPluginDescriptorException
{
PluginDescriptor pluginDescriptor = getPluginDescriptor( plugin, repositoryRequest );
MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( goal );
if ( mojoDescriptor == null )
{
throw new MojoNotFoundException( goal, pluginDescriptor );
}
return mojoDescriptor;
}
public void setupPluginRealm( PluginDescriptor pluginDescriptor, MavenSession session, ClassLoader parent,
List<String> imports )
throws PluginResolutionException, PluginManagerException
{
Plugin plugin = pluginDescriptor.getPlugin();
if ( plugin == null )
{
throw new IllegalArgumentException( "incomplete plugin descriptor, plugin missing" );
}
Artifact pluginArtifact = pluginDescriptor.getPluginArtifact();
if ( pluginArtifact == null )
{
throw new IllegalArgumentException( "incomplete plugin descriptor, plugin artifact missing" );
}
RepositoryRequest request = new DefaultRepositoryRequest();
request.setLocalRepository( session.getLocalRepository() );
request.setRemoteRepositories( session.getCurrentProject().getPluginArtifactRepositories() );
request.setCache( session.getRepositoryCache() );
request.setOffline( session.isOffline() );
List<Artifact> pluginArtifacts = resolvePluginArtifacts( plugin, pluginArtifact, request );
ClassRealm pluginRealm = classRealmManager.createPluginRealm( plugin, parent, imports );
if ( logger.isDebugEnabled() )
{
logger.debug( "Populating plugin realm for " + plugin.getId() );
}
List<Artifact> exposedPluginArtifacts = new ArrayList<Artifact>();
for ( Artifact artifact : pluginArtifacts )
{
if ( artifact.getFile() != null )
{
if ( logger.isDebugEnabled() )
{
logger.debug( " Included: " + artifact.getId() );
}
exposedPluginArtifacts.add( artifact );
try
{
pluginRealm.addURL( artifact.getFile().toURI().toURL() );
}
catch ( MalformedURLException e )
{
// Not going to happen
}
}
else
{
if ( logger.isDebugEnabled() )
{
logger.debug( " Excluded: " + artifact.getId() );
}
}
}
pluginDescriptor.setClassRealm( pluginRealm );
pluginDescriptor.setArtifacts( exposedPluginArtifacts );
try
{
for ( ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents() )
{
componentDescriptor.setRealm( pluginRealm );
container.addComponentDescriptor( componentDescriptor );
}
container.discoverComponents( pluginRealm );
}
catch ( PlexusConfigurationException e )
{
throw new PluginManagerException( plugin, e.getMessage(), e );
}
catch ( CycleDetectedInComponentGraphException e )
{
throw new PluginManagerException( plugin, e.getMessage(), e );
}
}
/**
* Gets all artifacts required for the class realm of the specified plugin. An artifact in the result list that has
* no file set is meant to be excluded from the plugin realm in favor of the equivalent library from the current
* core distro.
*/
private List<Artifact> resolvePluginArtifacts( Plugin plugin, Artifact pluginArtifact,
RepositoryRequest repositoryRequest )
throws PluginResolutionException
{
Set<Artifact> overrideArtifacts = new LinkedHashSet<Artifact>();
for ( Dependency dependency : plugin.getDependencies() )
{
overrideArtifacts.add( repositorySystem.createDependencyArtifact( dependency ) );
}
ArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME_PLUS_SYSTEM );
ArtifactResolutionRequest request = new ArtifactResolutionRequest( repositoryRequest );
request.setArtifact( pluginArtifact );
request.setArtifactDependencies( overrideArtifacts );
request.setFilter( filter );
request.setResolveRoot( true );
request.setResolveTransitively( true );
ArtifactResolutionResult result = repositorySystem.collect( request );
try
{
resolutionErrorHandler.throwErrors( request, result );
}
catch ( ArtifactResolutionException e )
{
throw new PluginResolutionException( plugin, e );
}
List<Artifact> pluginArtifacts = new ArrayList<Artifact>( result.getArtifacts() );
request.setResolveRoot( true ).setResolveTransitively( false ).setArtifactDependencies( null );
filter = artifactFilterManager.getCoreArtifactFilter();
for ( Artifact artifact : pluginArtifacts )
{
if ( filter.include( artifact ) )
{
result = repositorySystem.resolve( request.setArtifact( artifact ) );
try
{
resolutionErrorHandler.throwErrors( request, result );
}
catch ( ArtifactResolutionException e )
{
throw new PluginResolutionException( plugin, e );
}
}
else
{
artifact.setFile( null );
artifact.setResolved( false );
}
}
return pluginArtifacts;
}
public <T> T getConfiguredMojo( Class<T> mojoInterface, MavenSession session, MojoExecution mojoExecution )
throws PluginConfigurationException, PluginContainerException
{
MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
ClassRealm pluginRealm = pluginDescriptor.getClassRealm();
// We are forcing the use of the plugin realm for all lookups that might occur during
// the lifecycle that is part of the lookup. Here we are specifically trying to keep
// lookups that occur in contextualize calls in line with the right realm.
ClassRealm oldLookupRealm = container.setLookupRealm( pluginRealm );
container.setLookupRealm( pluginRealm );
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader( pluginRealm );
try
{
T mojo;
try
{
mojo = container.lookup( mojoInterface, mojoDescriptor.getRoleHint() );
}
catch ( ComponentLookupException e )
{
Throwable cause = e.getCause();
while ( cause != null && !( cause instanceof LinkageError )
&& !( cause instanceof ClassNotFoundException ) )
{
cause = cause.getCause();
}
if ( ( cause instanceof NoClassDefFoundError ) || ( cause instanceof ClassNotFoundException ) )
{
throw new PluginContainerException( mojoDescriptor, pluginRealm, "Unable to load the mojo '"
+ mojoDescriptor.getGoal() + "' in the plugin '" + pluginDescriptor.getId()
+ "'. A required class is missing: " + cause.getMessage(), e );
}
throw new PluginContainerException( mojoDescriptor, pluginRealm, "Unable to find the mojo '"
+ mojoDescriptor.getGoal() + "' (or one of its required components) in the plugin '"
+ pluginDescriptor.getId() + "'", e );
}
if ( mojo instanceof ContextEnabled )
{
MavenProject project = session.getCurrentProject();
Map<String, Object> pluginContext = session.getPluginContext( pluginDescriptor, project );
if ( pluginContext != null )
{
pluginContext.put( "project", project );
pluginContext.put( "pluginDescriptor", pluginDescriptor );
( (ContextEnabled) mojo ).setPluginContext( pluginContext );
}
}
if ( mojo instanceof Mojo )
{
( (Mojo) mojo ).setLog( new DefaultLog( logger ) );
}
Xpp3Dom dom = mojoExecution.getConfiguration();
PlexusConfiguration pomConfiguration;
if ( dom == null )
{
pomConfiguration = new XmlPlexusConfiguration( "configuration" );
}
else
{
pomConfiguration = new XmlPlexusConfiguration( dom );
}
ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator( session, mojoExecution );
populatePluginFields( mojo, mojoDescriptor, pluginRealm, pomConfiguration, expressionEvaluator );
return mojo;
}
finally
{
Thread.currentThread().setContextClassLoader( oldClassLoader );
container.setLookupRealm( oldLookupRealm );
}
}
private void populatePluginFields( Object mojo, MojoDescriptor mojoDescriptor, ClassRealm pluginRealm,
PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator )
throws PluginConfigurationException
{
ComponentConfigurator configurator = null;
String configuratorId = mojoDescriptor.getComponentConfigurator();
if ( StringUtils.isEmpty( configuratorId ) )
{
configuratorId = "basic";
}
try
{
// TODO: could the configuration be passed to lookup and the configurator known to plexus via the descriptor
// so that this method could entirely be handled by a plexus lookup?
configurator = container.lookup( ComponentConfigurator.class, configuratorId );
ConfigurationListener listener = new DebugConfigurationListener( logger );
logger.debug( "Configuring mojo '" + mojoDescriptor.getId() + "' with " + configuratorId
+ " configurator -->" );
configurator.configureComponent( mojo, configuration, expressionEvaluator, pluginRealm, listener );
logger.debug( "-- end configuration --" );
}
catch ( ComponentConfigurationException e )
{
throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
"Unable to parse the created DOM for mojo configuration", e );
}
catch ( ComponentLookupException e )
{
throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
"Unable to retrieve component configurator " + configuratorId
+ " for mojo 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 ( logger.isFatalErrorEnabled() )
{
logger.fatalError( configurator.getClass().getName()
+ "#configureComponent(...) caused a linkage error (" + e.getClass().getName()
+ ") and may be out-of-date. Check the realms:" );
StringBuilder sb = new StringBuilder();
sb.append( "Plugin realm = " + pluginRealm.getId() ).append( '\n' );
for ( int i = 0; i < pluginRealm.getURLs().length; i++ )
{
sb.append( "urls[" + i + "] = " + pluginRealm.getURLs()[i] );
if ( i != ( pluginRealm.getURLs().length - 1 ) )
{
sb.append( '\n' );
}
}
logger.fatalError( sb.toString() );
ClassRealm containerRealm = container.getContainerRealm();
sb = new StringBuilder();
sb.append( "Container realm = " + containerRealm.getId() ).append( '\n' );
for ( int i = 0; i < containerRealm.getURLs().length; i++ )
{
sb.append( "urls[" + i + "] = " + containerRealm.getURLs()[i] );
if ( i != ( containerRealm.getURLs().length - 1 ) )
{
sb.append( '\n' );
}
}
logger.fatalError( sb.toString() );
}
throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), e.getClass().getName() + ": "
+ e.getMessage(), new ComponentConfigurationException( e ) );
}
finally
{
if ( configurator != null )
{
try
{
container.release( configurator );
}
catch ( ComponentLifecycleException e )
{
logger.debug( "Failed to release mojo configurator - ignoring." );
}
}
}
}
public void releaseMojo( Object mojo, MojoExecution mojoExecution )
{
if ( mojo != null )
{
try
{
container.release( mojo );
}
catch ( ComponentLifecycleException e )
{
String goalExecId = mojoExecution.getGoal();
if ( mojoExecution.getExecutionId() != null )
{
goalExecId += " {execution: " + mojoExecution.getExecutionId() + "}";
}
logger.debug( "Error releasing mojo for " + goalExecId, e );
}
}
}
}

View File

@ -240,9 +240,11 @@ public class PluginManagerTest
RepositoryRequest repositoryRequest = new DefaultRepositoryRequest();
repositoryRequest.setLocalRepository( getLocalRepository() );
repositoryRequest.setRemoteRepositories( getPluginArtifactRepositories() );
List<Artifact> artifacts = pluginManager.getPluginArtifacts( pluginArtifact, plugin, repositoryRequest );
PluginDescriptor pluginDescriptor = pluginManager.loadPlugin( plugin, getRepositoryRequest( session ) );
pluginManager.getPluginRealm( session, pluginDescriptor );
List<Artifact> artifacts = pluginDescriptor.getArtifacts();
for ( Artifact a : artifacts )
{
if ( a.getGroupId().equals( "org.apache.maven.its.mng3586" ) && a.getArtifactId().equals( "tools" ) )