From ac8ff20611db82a4f8683412ac1a377e16d6313c Mon Sep 17 00:00:00 2001 From: John Dennis Casey Date: Tue, 16 Oct 2007 02:59:05 +0000 Subject: [PATCH] Adding project-level ClassRealm, which serves as a nexus for extensions. Extensions are loaded into separate ClassRealm instances, then scanned for components. These ComponentDescriptors are then used to add an import from the extension realm back to the project-session realm, and then the descriptor is added to the container with the project realm as its RealmId. From here, the registerWagons() method has been changed to use the map of projectSessions, and iterates through each project-level realm, setting the lookup-realm, then calling findAndRegisterWagons(..) for each. Also, the plugin manager has been changed to use the project-realm for loading plugins if it exists (the plugin realm becomes a child of the project realm, which should allow plugins to vary by project within a single reactor, though I haven't tested that yet). Also, shading the embedder to hide the jdom classes, and adjusting the assembly appropriately. Final thing: I'm rolling back some changes I accidentally made to the CLIManager the other day, which breaks the release plugin because the long options were removed for some reason (save action in Eclipse; don't ask). git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@585012 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/maven/DefaultMaven.java | 28 ++- .../src/main/java/org/apache/maven/Maven.java | 4 +- .../DefaultMavenExecutionResult.java | 8 + .../maven/execution/MavenExecutionResult.java | 2 + .../maven/execution/MavenProjectSession.java | 125 ++++++++++ .../apache/maven/execution/MavenSession.java | 19 +- .../maven/execution/ReactorManager.java | 4 +- .../extension/BuildExtensionScanner.java | 15 +- .../DefaultBuildExtensionScanner.java | 78 ++++--- .../extension/DefaultExtensionManager.java | 217 +++++++++++++++--- .../maven/extension/ExtensionManager.java | 16 +- .../extension/ExtensionManagerException.java | 128 +++++++++++ .../extension/ExtensionScanningException.java | 71 +++++- .../maven/plugin/DefaultPluginManager.java | 184 +++++++++------ .../plugin/PluginContainerException.java | 47 +++- .../maven/plugin/PluginManagerException.java | 71 ++++++ ...luginParameterExpressionEvaluatorTest.java | 2 +- maven-embedder/pom.xml | 34 +++ maven-embedder/src/main/assembly/bin.xml | 3 +- .../java/org/apache/maven/cli/CLIManager.java | 58 +++-- .../apache/maven/embedder/MavenEmbedder.java | 20 +- 21 files changed, 936 insertions(+), 198 deletions(-) create mode 100644 maven-core/src/main/java/org/apache/maven/execution/MavenProjectSession.java create mode 100644 maven-core/src/main/java/org/apache/maven/extension/ExtensionManagerException.java diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java index 2556fee4e2..6094b79147 100644 --- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java +++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java @@ -63,8 +63,10 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; /** * @author jason van zyl @@ -101,13 +103,13 @@ public class DefaultMaven // lifecycle execution public ReactorManager createReactorManager( MavenExecutionRequest request, - MavenExecutionResult result ) + MavenExecutionResult result, + Map projectSessions ) { List projects; - try { - projects = getProjects( request ); + projects = getProjects( request, projectSessions ); if ( projects.isEmpty() ) { @@ -164,9 +166,12 @@ public class DefaultMaven MavenExecutionResult result = new DefaultMavenExecutionResult(); + Map projectSessions = new HashMap(); + ReactorManager reactorManager = createReactorManager( request, - result ); + result, + projectSessions ); if ( result.hasExceptions() ) { @@ -184,7 +189,8 @@ public class DefaultMaven MavenSession session = createSession( request, reactorManager, - dispatcher ); + dispatcher, + projectSessions ); for ( Iterator i = request.getGoals().iterator(); i.hasNext(); ) { @@ -259,7 +265,7 @@ public class DefaultMaven systemContext.store( buildContextManager ); } - private List getProjects( MavenExecutionRequest request ) + private List getProjects( MavenExecutionRequest request, Map projectSessions ) throws MavenExecutionException { List projects; @@ -280,7 +286,7 @@ public class DefaultMaven // instances just-in-time. try { - buildExtensionScanner.scanForBuildExtensions( files, request.getLocalRepository(), request.getProfileManager() ); + buildExtensionScanner.scanForBuildExtensions( files, request.getLocalRepository(), request.getProfileManager(), projectSessions ); } catch ( ExtensionScanningException e ) { @@ -415,14 +421,16 @@ public class DefaultMaven // or not. protected MavenSession createSession( MavenExecutionRequest request, - ReactorManager rpm, - EventDispatcher dispatcher ) + ReactorManager reactorManager, + EventDispatcher dispatcher, + Map projectSessions ) { MavenSession session = new MavenSession( container, request, dispatcher, - rpm ); + reactorManager, + projectSessions ); SessionContext ctx = new SessionContext( session ); ctx.store( buildContextManager ); diff --git a/maven-core/src/main/java/org/apache/maven/Maven.java b/maven-core/src/main/java/org/apache/maven/Maven.java index e3db808757..80ec956cdd 100644 --- a/maven-core/src/main/java/org/apache/maven/Maven.java +++ b/maven-core/src/main/java/org/apache/maven/Maven.java @@ -23,6 +23,8 @@ import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenExecutionResult; import org.apache.maven.execution.ReactorManager; +import java.util.Map; + /** * @author Jason van Zyl * @version $Id$ @@ -53,5 +55,5 @@ public interface Maven MavenExecutionResult execute( MavenExecutionRequest request ); - ReactorManager createReactorManager( MavenExecutionRequest request, MavenExecutionResult result ); + ReactorManager createReactorManager( MavenExecutionRequest request, MavenExecutionResult result, Map projectSessions ); } \ No newline at end of file diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java index 1e4dff357a..6603b0285f 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java +++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java @@ -21,6 +21,7 @@ package org.apache.maven.execution; import org.apache.maven.BuildFailureException; import org.apache.maven.artifact.resolver.ArtifactResolutionResult; +import org.apache.maven.extension.ExtensionScanningException; import org.apache.maven.lifecycle.LifecycleExecutionException; import org.apache.maven.project.DuplicateProjectException; import org.apache.maven.project.MavenProject; @@ -85,6 +86,13 @@ public class DefaultMavenExecutionResult return exceptions; } + public MavenExecutionResult addExtensionScanningException( ExtensionScanningException e ) + { + addException( e ); + + return this; + } + public MavenExecutionResult addProjectBuildingException( ProjectBuildingException e ) { addException( e ); diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java index ca08343f15..747748d0f1 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java +++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java @@ -21,6 +21,7 @@ package org.apache.maven.execution; import org.apache.maven.BuildFailureException; import org.apache.maven.artifact.resolver.ArtifactResolutionResult; +import org.apache.maven.extension.ExtensionScanningException; import org.apache.maven.lifecycle.LifecycleExecutionException; import org.apache.maven.project.DuplicateProjectException; import org.apache.maven.project.MavenProject; @@ -58,6 +59,7 @@ public interface MavenExecutionResult MavenExecutionResult addBuildFailureException( BuildFailureException buildFailureException ); MavenExecutionResult addMavenExecutionException( MavenExecutionException e ); MavenExecutionResult addProjectBuildingException (ProjectBuildingException e ); + MavenExecutionResult addExtensionScanningException( ExtensionScanningException e ); MavenExecutionResult addUnknownException( Throwable t ); boolean hasExceptions(); diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenProjectSession.java b/maven-core/src/main/java/org/apache/maven/execution/MavenProjectSession.java new file mode 100644 index 0000000000..39c5c490ba --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/execution/MavenProjectSession.java @@ -0,0 +1,125 @@ +package org.apache.maven.execution; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.ArtifactUtils; +import org.apache.maven.model.Plugin; +import org.apache.maven.plugin.descriptor.PluginDescriptor; +import org.codehaus.plexus.PlexusContainer; +import org.codehaus.plexus.PlexusContainerException; +import org.codehaus.plexus.classworlds.realm.ClassRealm; +import org.codehaus.plexus.classworlds.realm.DuplicateRealmException; +import org.codehaus.plexus.classworlds.realm.NoSuchRealmException; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class MavenProjectSession +{ + + private Map componentRealms = new HashMap(); + + private String projectId; + + private ClassRealm projectRealm; + + private final PlexusContainer container; + + public MavenProjectSession( String projectId, + PlexusContainer container ) + throws PlexusContainerException + { + this.projectId = projectId; + this.container = container; + projectRealm = container.createComponentRealm( projectId, Collections.EMPTY_LIST ); + } + + public String getProjectId() + { + return projectId; + } + + public void addComponentRealm( ClassRealm realm ) + { + componentRealms.put( realm.getId(), realm ); + } + + public static String createRealmId( Artifact realmArtifact ) + { + return ArtifactUtils.versionlessKey( realmArtifact ); + } + + public boolean containsRealm( Artifact extensionArtifact ) + { + String id = createRealmId( extensionArtifact ); + return componentRealms.containsKey( id ); + } + + public boolean containsRealm( Plugin plugin ) + { + String id = createRealmId( plugin ); + return componentRealms.containsKey( id ); + } + + public ClassRealm getProjectRealm() + { + return projectRealm; + } + + public ClassRealm createExtensionRealm( Artifact extensionArtifact ) + throws DuplicateRealmException + { + String realmId = MavenProjectSession.createRealmId( extensionArtifact ); + ClassRealm extRealm = container.getContainerRealm().createChildRealm( projectId + "/" + realmId ); + + componentRealms.put( realmId, extRealm ); + + return extRealm; + } + + public static String createProjectId( String groupId, + String artifactId, + String version ) + { + return groupId + ":" + artifactId + ":" + version; + } + + public ClassRealm getComponentRealm( String key ) + { + return (ClassRealm) componentRealms.get( key ); + } + + + public ClassRealm createPluginRealm( Plugin projectPlugin ) + throws DuplicateRealmException + { + String realmId = MavenProjectSession.createRealmId( projectPlugin ); + ClassRealm extRealm = projectRealm.createChildRealm( realmId ); + + componentRealms.put( realmId, extRealm ); + + return extRealm; + } + + public static String createRealmId( Plugin plugin ) + { + return ArtifactUtils.versionlessKey( plugin.getGroupId(), plugin.getArtifactId() ); + } + + public static String createRealmId( PluginDescriptor pd ) + { + return ArtifactUtils.versionlessKey( pd.getGroupId(), pd.getArtifactId() ); + } + + public ClassRealm getPluginRealm( PluginDescriptor pluginDescriptor ) + throws NoSuchRealmException + { + String realmId = MavenProjectSession.createRealmId( pluginDescriptor ); + ClassRealm extRealm = projectRealm.getWorld().getRealm( realmId ); + + componentRealms.put( realmId, extRealm ); + + return extRealm; + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java b/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java index 05b793f30c..42239ded59 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java +++ b/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java @@ -27,7 +27,6 @@ import org.apache.maven.settings.Settings; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; -import java.io.File; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; @@ -51,11 +50,14 @@ public class MavenSession private MavenExecutionRequest request; private Map reports = new LinkedHashMap(); - + + private final Map projectSessions; + public MavenSession( PlexusContainer container, MavenExecutionRequest request, EventDispatcher eventDispatcher, - ReactorManager reactorManager ) + ReactorManager reactorManager, + Map projectSessions ) { this.container = container; @@ -64,6 +66,15 @@ public class MavenSession this.eventDispatcher = eventDispatcher; this.reactorManager = reactorManager; + + this.projectSessions = projectSessions; + } + + public MavenProjectSession getProjectSession( MavenProject project ) + { + String id = MavenProjectSession.createProjectId( project.getGroupId(), project.getArtifactId(), project.getVersion() ); + + return (MavenProjectSession) projectSessions.get( id ); } public Map getPluginContext( PluginDescriptor pluginDescriptor, @@ -155,5 +166,5 @@ public class MavenSession { return request; } - + } \ No newline at end of file diff --git a/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java b/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java index e473adf1ef..095f10e7da 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java +++ b/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java @@ -56,7 +56,7 @@ public class ReactorManager public ReactorManager( List projects, String failureBehavior ) throws CycleDetectedException, DuplicateProjectException { - this.sorter = new ProjectSorter( projects ); + sorter = new ProjectSorter( projects ); if ( failureBehavior == null ) { @@ -108,7 +108,7 @@ public class ReactorManager List dependents = sorter.getDependents( id ); - if ( dependents != null && !dependents.isEmpty() ) + if ( ( dependents != null ) && !dependents.isEmpty() ) { for ( Iterator it = dependents.iterator(); it.hasNext(); ) { diff --git a/maven-core/src/main/java/org/apache/maven/extension/BuildExtensionScanner.java b/maven-core/src/main/java/org/apache/maven/extension/BuildExtensionScanner.java index c3906e24a7..21243c9f15 100644 --- a/maven-core/src/main/java/org/apache/maven/extension/BuildExtensionScanner.java +++ b/maven-core/src/main/java/org/apache/maven/extension/BuildExtensionScanner.java @@ -24,16 +24,23 @@ import org.apache.maven.profiles.ProfileManager; import java.io.File; import java.util.List; +import java.util.Map; public interface BuildExtensionScanner { - + String ROLE = BuildExtensionScanner.class.getName(); - - void scanForBuildExtensions( List files, ArtifactRepository localRepository, ProfileManager globalProfileManager ) + + void scanForBuildExtensions( List files, + ArtifactRepository localRepository, + ProfileManager globalProfileManager, + Map projectSessions ) throws ExtensionScanningException; - void scanForBuildExtensions( File pom, ArtifactRepository localRepository, ProfileManager globalProfileManager ) + void scanForBuildExtensions( File pom, + ArtifactRepository localRepository, + ProfileManager globalProfileManager, + Map projectSessions ) throws ExtensionScanningException; } diff --git a/maven-core/src/main/java/org/apache/maven/extension/DefaultBuildExtensionScanner.java b/maven-core/src/main/java/org/apache/maven/extension/DefaultBuildExtensionScanner.java index 9273ecf75f..4b57fdcb77 100644 --- a/maven-core/src/main/java/org/apache/maven/extension/DefaultBuildExtensionScanner.java +++ b/maven-core/src/main/java/org/apache/maven/extension/DefaultBuildExtensionScanner.java @@ -21,8 +21,6 @@ package org.apache.maven.extension; import org.apache.maven.artifact.ArtifactUtils; 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.context.BuildContextManager; import org.apache.maven.model.Build; import org.apache.maven.model.Extension; @@ -38,7 +36,6 @@ import org.apache.maven.project.build.model.ModelLineageBuilder; import org.apache.maven.project.build.model.ModelLineageIterator; import org.apache.maven.project.interpolation.ModelInterpolationException; import org.apache.maven.project.interpolation.ModelInterpolator; -import org.codehaus.plexus.PlexusContainerException; import org.codehaus.plexus.logging.LogEnabled; import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.logging.console.ConsoleLogger; @@ -69,8 +66,10 @@ public class DefaultBuildExtensionScanner private ModelInterpolator modelInterpolator; - public void scanForBuildExtensions( List files, ArtifactRepository localRepository, - ProfileManager globalProfileManager ) + public void scanForBuildExtensions( List files, + ArtifactRepository localRepository, + ProfileManager globalProfileManager, + Map projectSessions ) throws ExtensionScanningException { List visited = new ArrayList(); @@ -79,21 +78,27 @@ public class DefaultBuildExtensionScanner { File pom = (File) it.next(); - scanInternal( pom, localRepository, globalProfileManager, visited, files ); + scanInternal( pom, localRepository, globalProfileManager, visited, files, projectSessions ); } } - public void scanForBuildExtensions( File pom, ArtifactRepository localRepository, - ProfileManager globalProfileManager ) + public void scanForBuildExtensions( File pom, + ArtifactRepository localRepository, + ProfileManager globalProfileManager, + Map projectSessions ) throws ExtensionScanningException { - scanInternal( pom, localRepository, globalProfileManager, new ArrayList(), Collections.singletonList( pom ) ); + scanInternal( pom, localRepository, globalProfileManager, new ArrayList(), Collections.singletonList( pom ), projectSessions ); } // TODO: Use a build-context cache object for visitedModelIdx and reactorFiles, // once we move to just-in-time project scanning. - private void scanInternal( File pom, ArtifactRepository localRepository, ProfileManager globalProfileManager, - List visitedModelIds, List reactorFiles ) + private void scanInternal( File pom, + ArtifactRepository localRepository, + ProfileManager globalProfileManager, + List visitedModelIds, + List reactorFiles, + Map projectSessions ) throws ExtensionScanningException { @@ -150,7 +155,7 @@ public class DefaultBuildExtensionScanner model = modelInterpolator.interpolate( model, inheritedInterpolationValues, false ); - checkModelBuildForExtensions( model, localRepository, inheritedRemoteRepositories ); + checkModelBuildForExtensions( model, localRepository, inheritedRemoteRepositories, projectSessions ); if ( !reactorFiles.contains( modelPom ) ) { @@ -160,8 +165,14 @@ public class DefaultBuildExtensionScanner } else { - checkModulesForExtensions( modelPom, model, localRepository, originalRemoteRepositories, - globalProfileManager, visitedModelIds, reactorFiles ); + checkModulesForExtensions( modelPom, + model, + localRepository, + originalRemoteRepositories, + globalProfileManager, + visitedModelIds, + reactorFiles, + projectSessions ); } Properties modelProps = model.getProperties(); @@ -173,12 +184,12 @@ public class DefaultBuildExtensionScanner getLogger().debug( "Finished pre-scanning: " + pom + " for build extensions." ); - extensionManager.registerWagons(); + extensionManager.registerWagons( projectSessions ); } catch ( ModelInterpolationException e ) { throw new ExtensionScanningException( "Failed to interpolate model from: " + pom - + " prior to scanning for extensions.", e ); + + " prior to scanning for extensions.", pom, e ); } finally { @@ -202,9 +213,14 @@ public class DefaultBuildExtensionScanner return groupId + ":" + artifactId; } - private void checkModulesForExtensions( File containingPom, Model model, ArtifactRepository localRepository, - List originalRemoteRepositories, ProfileManager globalProfileManager, - List visitedModelIds, List reactorFiles ) + private void checkModulesForExtensions( File containingPom, + Model model, + ArtifactRepository localRepository, + List originalRemoteRepositories, + ProfileManager globalProfileManager, + List visitedModelIds, + List reactorFiles, + Map projectSessions ) throws ExtensionScanningException { // FIXME: This gets a little sticky, because modules can be added by profiles that require @@ -250,7 +266,7 @@ public class DefaultBuildExtensionScanner } catch ( IOException e ) { - throw new ExtensionScanningException( "Error getting canonical path for modulePomDirectory.", e ); + throw new ExtensionScanningException( "Error getting canonical path for modulePomDirectory.", containingPom, moduleSubpath, e ); } if ( modulePomDirectory.isDirectory() ) @@ -270,12 +286,12 @@ public class DefaultBuildExtensionScanner continue; } - scanInternal( modulePomDirectory, localRepository, globalProfileManager, visitedModelIds, reactorFiles ); + scanInternal( modulePomDirectory, localRepository, globalProfileManager, visitedModelIds, reactorFiles, projectSessions ); } } } - private void checkModelBuildForExtensions( Model model, ArtifactRepository localRepository, List remoteRepositories ) + private void checkModelBuildForExtensions( Model model, ArtifactRepository localRepository, List remoteRepositories, Map projectSessions ) throws ExtensionScanningException { Build build = model.getBuild(); @@ -299,22 +315,12 @@ public class DefaultBuildExtensionScanner try { - extensionManager.addExtension( extension, model, remoteRepositories, localRepository ); + extensionManager.addExtension( extension, model, remoteRepositories, localRepository, projectSessions ); } - catch ( ArtifactResolutionException e ) + catch ( ExtensionManagerException e ) { throw new ExtensionScanningException( "Cannot resolve pre-scanned extension artifact: " - + extension.getGroupId() + ":" + extension.getArtifactId() + ": " + e.getMessage(), e ); - } - catch ( ArtifactNotFoundException e ) - { - throw new ExtensionScanningException( "Cannot find pre-scanned extension artifact: " - + extension.getGroupId() + ":" + extension.getArtifactId() + ": " + e.getMessage(), e ); - } - catch ( PlexusContainerException e ) - { - throw new ExtensionScanningException( "Failed to add pre-scanned extension: " - + extension.getGroupId() + ":" + extension.getArtifactId() + ": " + e.getMessage(), e ); + + extension.getGroupId() + ":" + extension.getArtifactId() + ": " + e.getMessage(), model, extension, e ); } } } @@ -336,7 +342,7 @@ public class DefaultBuildExtensionScanner catch ( ProjectBuildingException e ) { throw new ExtensionScanningException( "Error building model lineage in order to pre-scan for extensions: " - + e.getMessage(), e ); + + e.getMessage(), pom, e ); } return lineage; diff --git a/maven-core/src/main/java/org/apache/maven/extension/DefaultExtensionManager.java b/maven-core/src/main/java/org/apache/maven/extension/DefaultExtensionManager.java index bf2bc1bee5..faf1821108 100644 --- a/maven-core/src/main/java/org/apache/maven/extension/DefaultExtensionManager.java +++ b/maven-core/src/main/java/org/apache/maven/extension/DefaultExtensionManager.java @@ -20,40 +20,55 @@ package org.apache.maven.extension; */ import org.apache.maven.ArtifactFilterManager; -import org.apache.maven.plugin.DefaultPluginManager; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.ArtifactUtils; -import org.apache.maven.artifact.versioning.VersionRange; -import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; -import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.manager.WagonManager; +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.metadata.ArtifactMetadataRetrievalException; 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.filter.ArtifactFilter; +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.MavenProjectSession; import org.apache.maven.model.Extension; import org.apache.maven.model.Model; import org.apache.maven.model.Parent; +import org.apache.maven.plugin.DefaultPluginManager; import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.MutablePlexusContainer; import org.codehaus.plexus.PlexusConstants; -import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.PlexusContainerException; +import org.codehaus.plexus.classworlds.realm.ClassRealm; +import org.codehaus.plexus.classworlds.realm.DuplicateRealmException; +import org.codehaus.plexus.classworlds.realm.NoSuchRealmException; +import org.codehaus.plexus.component.discovery.ComponentDiscoverer; +import org.codehaus.plexus.component.discovery.ComponentDiscovererManager; +import org.codehaus.plexus.component.discovery.ComponentDiscoveryEvent; +import org.codehaus.plexus.component.discovery.ComponentDiscoveryListener; +import org.codehaus.plexus.component.discovery.DefaultComponentDiscoverer; +import org.codehaus.plexus.component.repository.ComponentDescriptor; +import org.codehaus.plexus.component.repository.ComponentSetDescriptor; +import org.codehaus.plexus.component.repository.exception.ComponentRepositoryException; +import org.codehaus.plexus.configuration.PlexusConfigurationException; 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 java.net.MalformedURLException; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.HashSet; /** * Used to locate extensions. @@ -73,7 +88,7 @@ public class DefaultExtensionManager private ArtifactMetadataSource artifactMetadataSource; - private PlexusContainer container; + private MutablePlexusContainer container; private ArtifactFilterManager artifactFilterManager; @@ -82,8 +97,8 @@ public class DefaultExtensionManager public void addExtension( Extension extension, Model originatingModel, List remoteRepositories, - ArtifactRepository localRepository ) - throws ArtifactResolutionException, PlexusContainerException, ArtifactNotFoundException + ArtifactRepository localRepository, Map projectSessions ) + throws ExtensionManagerException { Artifact extensionArtifact = artifactFactory.createBuildArtifact( extension.getGroupId(), extension.getArtifactId(), @@ -109,13 +124,19 @@ public class DefaultExtensionManager Artifact projectArtifact = artifactFactory.createProjectArtifact( groupId, artifactId, version ); - addExtension( extensionArtifact, projectArtifact, remoteRepositories, localRepository, null ); + addExtension( extensionArtifact, + projectArtifact, + remoteRepositories, + localRepository, + null, + projectSessions, + MavenProjectSession.createProjectId( groupId, artifactId, version ) ); } public void addExtension( Extension extension, MavenProject project, - ArtifactRepository localRepository ) - throws ArtifactResolutionException, PlexusContainerException, ArtifactNotFoundException + ArtifactRepository localRepository, Map projectSessions ) + throws ExtensionManagerException { String extensionId = ArtifactUtils.versionlessKey( extension.getGroupId(), extension.getArtifactId() ); @@ -123,24 +144,47 @@ public class DefaultExtensionManager Artifact artifact = (Artifact) project.getExtensionArtifactMap().get( extensionId ); - addExtension( artifact, project.getArtifact(), project.getRemoteArtifactRepositories(), - localRepository, new ActiveArtifactResolver( project ) ); + addExtension( artifact, + project.getArtifact(), + project.getRemoteArtifactRepositories(), + localRepository, + new ActiveArtifactResolver( project ), + projectSessions, + MavenProjectSession.createProjectId( project.getGroupId(), project.getArtifactId(), project.getVersion() ) ); } private void addExtension( Artifact extensionArtifact, Artifact projectArtifact, List remoteRepositories, - ArtifactRepository localRepository, ActiveArtifactResolver activeArtifactResolver ) - throws ArtifactResolutionException, PlexusContainerException, ArtifactNotFoundException + ArtifactRepository localRepository, + ActiveArtifactResolver activeArtifactResolver, + Map projectSessions, + String projectId ) + throws ExtensionManagerException { getLogger().debug( "Starting extension-addition process for: " + extensionArtifact ); - if ( extensionArtifact != null ) + MavenProjectSession projectSession = (MavenProjectSession) projectSessions.get( projectId ); + if ( projectSession == null ) + { + try + { + projectSession = new MavenProjectSession( projectId, container ); + } + catch ( PlexusContainerException e ) + { + throw new ExtensionManagerException( "Failed to create project realm for: " + projectId, projectId, e ); + } + + projectSessions.put( projectId, projectSession ); + } + + // if the extension is null, or if it's already been added to the current project-session, skip it. + if ( ( extensionArtifact != null ) && !projectSession.containsRealm( extensionArtifact ) ) { ArtifactFilter filter = new ProjectArtifactExceptionFilter( artifactFilterManager.getArtifactFilter(), projectArtifact ); - ResolutionGroup resolutionGroup; try @@ -149,8 +193,8 @@ public class DefaultExtensionManager } catch ( ArtifactMetadataRetrievalException e ) { - throw new ArtifactResolutionException( "Unable to download metadata from repository for plugin '" + - extensionArtifact.getId() + "': " + e.getMessage(), extensionArtifact, e ); + throw new ExtensionManagerException( "Unable to download metadata from repository for extension artifact '" + + extensionArtifact.getId() + "': " + e.getMessage(), extensionArtifact, projectId, e ); } // We use the same hack here to make sure that plexus 1.1 is available for extensions that do @@ -162,10 +206,33 @@ public class DefaultExtensionManager dependencies.add( extensionArtifact ); // TODO: Make this work with managed dependencies, or an analogous management section in the POM. - ArtifactResolutionResult result = - artifactResolver.resolveTransitively( dependencies, projectArtifact, + ArtifactResolutionResult result; + try + { + result = artifactResolver.resolveTransitively( dependencies, projectArtifact, Collections.EMPTY_MAP, localRepository, remoteRepositories, artifactMetadataSource, filter ); + } + catch ( ArtifactResolutionException e ) + { + throw new ExtensionManagerException( "Unable to resolve one or more extension artifacts for: " + extensionArtifact.getId(), extensionArtifact, projectId, e ); + } + catch ( ArtifactNotFoundException e ) + { + throw new ExtensionManagerException( "One or more extension artifacts is missing for: " + extensionArtifact.getId(), extensionArtifact, projectId, e ); + } + + ClassRealm extensionRealm; + try + { + extensionRealm = projectSession.createExtensionRealm( extensionArtifact ); + } + catch ( DuplicateRealmException e ) + { + throw new ExtensionManagerException( "Unable to create extension ClassRealm for extension: " + extensionArtifact.getId() + " within session for project: " + projectId, extensionArtifact, projectId, e ); + } + + projectSession.addComponentRealm( extensionRealm ); for ( Iterator i = result.getArtifacts().iterator(); i.hasNext(); ) { @@ -176,24 +243,78 @@ public class DefaultExtensionManager a = activeArtifactResolver.replaceWithActiveArtifact( a ); } - getLogger().debug( "Adding to extension classpath: " + a.getFile() + " in classRealm: " + container.getContainerRealm().getId() ); + getLogger().debug( "Adding to extension classpath: " + a.getFile() + " in classRealm: " + extensionRealm.getId() ); - container.addJarResource( a.getFile() ); + try + { + extensionRealm.addURL( a.getFile().toURL() ); + } + catch ( MalformedURLException e ) + { + throw new ExtensionManagerException( "Unable to generate URL from extension artifact file: " + a.getFile(), extensionArtifact, projectId, e ); + } + } - artifactFilterManager.excludeArtifact( a.getArtifactId() ); + ComponentDiscoverer discoverer = new DefaultComponentDiscoverer(); + discoverer.setManager( new DummyDiscovererManager() ); + + ClassRealm projectRealm = projectSession.getProjectRealm(); + try + { + List componentSetDescriptors = discoverer.findComponents( container.getContext(), extensionRealm ); + for ( Iterator it = componentSetDescriptors.iterator(); it.hasNext(); ) + { + ComponentSetDescriptor compSet = (ComponentSetDescriptor) it.next(); + for ( Iterator compIt = compSet.getComponents().iterator(); compIt.hasNext(); ) + { + ComponentDescriptor comp = (ComponentDescriptor) compIt.next(); + String implementation = comp.getImplementation(); + + try + { + getLogger().debug( "Importing: " + implementation + " from extension realm: " + extensionRealm.getId() + " to project realm: " + projectRealm.getId() ); + + projectRealm.importFrom( extensionRealm.getId(), implementation ); + + comp.setRealmId( projectRealm.getId() ); + container.addComponentDescriptor( comp ); + } + catch ( NoSuchRealmException e ) + { + throw new ExtensionManagerException( "Failed to create import for component: " + implementation + " from extension realm: " + extensionRealm.getId() + " to project realm: " + projectRealm.getId(), extensionArtifact, projectId, e ); + } + } + } + } + catch ( PlexusConfigurationException e ) + { + throw new ExtensionManagerException( "Unable to discover extension components.", extensionArtifact, projectId, e ); + } + catch ( ComponentRepositoryException e ) + { + throw new ExtensionManagerException( "Unable to discover extension components from imports added to project-session realm.", extensionArtifact, projectId, e ); } } } - public void registerWagons() + public void registerWagons( Map projectSessions ) { - wagonManager.findAndRegisterWagons( container ); + for ( Iterator it = projectSessions.values().iterator(); it.hasNext(); ) + { + MavenProjectSession projectSession = (MavenProjectSession) it.next(); + + ClassRealm oldRealm = container.setLookupRealm( projectSession.getProjectRealm() ); + + wagonManager.findAndRegisterWagons( container ); + + container.setLookupRealm( oldRealm ); + } } public void contextualize( Context context ) throws ContextException { - container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY ); + container = (MutablePlexusContainer) context.get( PlexusConstants.PLEXUS_KEY ); } private static final class ActiveArtifactResolver @@ -281,5 +402,41 @@ public class DefaultExtensionManager "plexus-utils", "1.1", Artifact.SCOPE_RUNTIME, "jar" ) ); } - } + } + + private static final class DummyDiscovererManager implements ComponentDiscovererManager + { + + public void fireComponentDiscoveryEvent( ComponentDiscoveryEvent arg0 ) + { + } + + public List getComponentDiscoverers() + { + return null; + } + + public Map getComponentDiscoveryListeners() + { + return null; + } + + public List getListeners() + { + return null; + } + + public void initialize() + { + } + + public void registerComponentDiscoveryListener( ComponentDiscoveryListener arg0 ) + { + } + + public void removeComponentDiscoveryListener( ComponentDiscoveryListener arg0 ) + { + } + + } } diff --git a/maven-core/src/main/java/org/apache/maven/extension/ExtensionManager.java b/maven-core/src/main/java/org/apache/maven/extension/ExtensionManager.java index f84e2477df..8af81f87e2 100644 --- a/maven-core/src/main/java/org/apache/maven/extension/ExtensionManager.java +++ b/maven-core/src/main/java/org/apache/maven/extension/ExtensionManager.java @@ -20,14 +20,12 @@ package org.apache.maven.extension; */ 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.model.Extension; import org.apache.maven.model.Model; import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.PlexusContainerException; import java.util.List; +import java.util.Map; /** * Used to locate extensions. @@ -37,12 +35,12 @@ import java.util.List; */ public interface ExtensionManager { - void addExtension( Extension extension, MavenProject project, ArtifactRepository localRepository ) - throws ArtifactResolutionException, PlexusContainerException, ArtifactNotFoundException; - - void registerWagons(); + void addExtension( Extension extension, MavenProject project, ArtifactRepository localRepository, Map projectSessions ) + throws ExtensionManagerException; + + void registerWagons( Map projectSessions ); void addExtension( Extension extension, Model originatingModel, List remoteRepositories, - ArtifactRepository localRepository ) - throws ArtifactResolutionException, PlexusContainerException, ArtifactNotFoundException; + ArtifactRepository localRepository, Map projectSessions ) + throws ExtensionManagerException; } diff --git a/maven-core/src/main/java/org/apache/maven/extension/ExtensionManagerException.java b/maven-core/src/main/java/org/apache/maven/extension/ExtensionManagerException.java new file mode 100644 index 0000000000..f7d81904c8 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/extension/ExtensionManagerException.java @@ -0,0 +1,128 @@ +package org.apache.maven.extension; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException; +import org.apache.maven.artifact.resolver.ArtifactNotFoundException; +import org.apache.maven.artifact.resolver.ArtifactResolutionException; +import org.codehaus.plexus.PlexusContainerException; +import org.codehaus.plexus.classworlds.realm.DuplicateRealmException; +import org.codehaus.plexus.classworlds.realm.NoSuchRealmException; +import org.codehaus.plexus.component.repository.exception.ComponentRepositoryException; +import org.codehaus.plexus.configuration.PlexusConfigurationException; + +import java.net.MalformedURLException; + +public class ExtensionManagerException + extends Exception +{ + + private Artifact extensionArtifact; + private final String projectId; + + public ExtensionManagerException( String message, + Artifact extensionArtifact, + String projectId, + ArtifactMetadataRetrievalException cause ) + { + super( message, cause ); + this.extensionArtifact = extensionArtifact; + this.projectId = projectId; + } + + public ExtensionManagerException( String message, + Artifact extensionArtifact, + String projectId, + DuplicateRealmException cause ) + { + super( message, cause ); + this.extensionArtifact = extensionArtifact; + this.projectId = projectId; + } + + public ExtensionManagerException( String message, + Artifact extensionArtifact, + String projectId, + ArtifactResolutionException cause ) + { + super( message, cause ); + this.extensionArtifact = extensionArtifact; + this.projectId = projectId; + } + + public ExtensionManagerException( String message, + Artifact extensionArtifact, + String projectId, + ArtifactNotFoundException cause ) + { + super( message, cause ); + this.extensionArtifact = extensionArtifact; + this.projectId = projectId; + } + + public ExtensionManagerException( String message, + Artifact extensionArtifact, + String projectId, + MalformedURLException cause ) + { + super( message, cause ); + this.extensionArtifact = extensionArtifact; + this.projectId = projectId; + } + + public ExtensionManagerException( String message, + Artifact extensionArtifact, + String projectId, + PlexusConfigurationException cause ) + { + super( message, cause ); + this.extensionArtifact = extensionArtifact; + this.projectId = projectId; + } + + public ExtensionManagerException( String message, + String projectId, + DuplicateRealmException cause ) + { + super( message, cause ); + this.projectId = projectId; + } + + public ExtensionManagerException( String message, + Artifact extensionArtifact, + String projectId, + NoSuchRealmException cause ) + { + super( message, cause ); + this.extensionArtifact = extensionArtifact; + this.projectId = projectId; + } + + public ExtensionManagerException( String message, + String projectId, + PlexusContainerException cause ) + { + super( message, cause ); + this.projectId = projectId; + } + + public ExtensionManagerException( String message, + Artifact extensionArtifact, + String projectId, + ComponentRepositoryException cause ) + { + super( message, cause ); + this.extensionArtifact = extensionArtifact; + this.projectId = projectId; + } + + public Artifact getExtensionArtifact() + { + return extensionArtifact; + } + + public String getProjectId() + { + return projectId; + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/extension/ExtensionScanningException.java b/maven-core/src/main/java/org/apache/maven/extension/ExtensionScanningException.java index 43c148c384..f516b3352b 100644 --- a/maven-core/src/main/java/org/apache/maven/extension/ExtensionScanningException.java +++ b/maven-core/src/main/java/org/apache/maven/extension/ExtensionScanningException.java @@ -1,5 +1,13 @@ package org.apache.maven.extension; +import org.apache.maven.model.Extension; +import org.apache.maven.model.Model; +import org.apache.maven.project.ProjectBuildingException; +import org.apache.maven.project.interpolation.ModelInterpolationException; + +import java.io.File; +import java.io.IOException; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -23,14 +31,71 @@ public class ExtensionScanningException extends Exception { - public ExtensionScanningException( String message, Throwable cause ) + private File pomFile; + private String extensionId; + private String modelId; + private String moduleSubpath; + + public ExtensionScanningException( String message, + File pomFile, + ProjectBuildingException cause ) + { + super( message, cause ); + this.pomFile = pomFile; + } + + public ExtensionScanningException( String message, + Model model, + Extension extension, + ExtensionManagerException cause ) + { + super( message, cause ); + modelId = model.getId(); + extensionId = extension.getGroupId() + ":" + extension.getArtifactId(); + } + + public ExtensionScanningException( String message, + ProjectBuildingException cause ) { super( message, cause ); } - public ExtensionScanningException( String message ) + public ExtensionScanningException( String message, + File pomFile, + String moduleSubpath, + IOException cause ) { - super( message ); + super( message, cause ); + this.pomFile = pomFile; + this.moduleSubpath = moduleSubpath; + } + + public ExtensionScanningException( String message, + File pomFile, + ModelInterpolationException cause ) + { + super( message, cause ); + this.pomFile = pomFile; + } + + public File getPomFile() + { + return pomFile; + } + + public String getExtensionId() + { + return extensionId; + } + + public String getModelId() + { + return modelId; + } + + public String getModuleSubpath() + { + return moduleSubpath; } } diff --git a/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginManager.java index 6d6dfe2c18..0cc42b7ea4 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginManager.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginManager.java @@ -36,6 +36,7 @@ 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.context.BuildContextManager; +import org.apache.maven.execution.MavenProjectSession; import org.apache.maven.execution.MavenSession; import org.apache.maven.execution.RuntimeInformation; import org.apache.maven.lifecycle.LifecycleExecutionContext; @@ -60,10 +61,12 @@ 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.codehaus.plexus.MutablePlexusContainer; import org.codehaus.plexus.PlexusConstants; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.PlexusContainerException; import org.codehaus.plexus.classworlds.realm.ClassRealm; +import org.codehaus.plexus.classworlds.realm.DuplicateRealmException; import org.codehaus.plexus.classworlds.realm.NoSuchRealmException; import org.codehaus.plexus.component.configurator.ComponentConfigurationException; import org.codehaus.plexus.component.configurator.ComponentConfigurator; @@ -72,7 +75,9 @@ import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluatio import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.codehaus.plexus.component.repository.exception.ComponentRepositoryException; import org.codehaus.plexus.configuration.PlexusConfiguration; +import org.codehaus.plexus.configuration.PlexusConfigurationException; import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; import org.codehaus.plexus.context.Context; import org.codehaus.plexus.context.ContextException; @@ -81,6 +86,7 @@ import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.xml.Xpp3Dom; +import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -106,7 +112,7 @@ public class DefaultPluginManager RESERVED_GROUP_IDS = rgids; } - protected PlexusContainer container; + protected MutablePlexusContainer container; protected PluginDescriptorBuilder pluginDescriptorBuilder; @@ -189,21 +195,11 @@ public class DefaultPluginManager throws PluginVersionResolutionException, ArtifactNotFoundException, ArtifactResolutionException, InvalidPluginException, PluginManagerException, PluginNotFoundException - { - ArtifactRepository localRepository = session.getLocalRepository(); - - return verifyVersionedPlugin( plugin, project, localRepository ); - } - - private PluginDescriptor verifyVersionedPlugin( Plugin plugin, - MavenProject project, - ArtifactRepository localRepository ) - throws PluginVersionResolutionException, ArtifactNotFoundException, - ArtifactResolutionException, InvalidPluginException, - PluginManagerException, PluginNotFoundException { getLogger().debug( "In verifyVersionedPlugin for: " + plugin.getKey() ); + ArtifactRepository localRepository = session.getLocalRepository(); + // 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 @@ -241,7 +237,7 @@ public class DefaultPluginManager artifactResolver.resolve( pluginArtifact, project.getPluginArtifactRepositories(), localRepository ); - addPlugin( plugin, pluginArtifact, project, localRepository ); + addPlugin( plugin, pluginArtifact, project, session ); } else { @@ -323,32 +319,6 @@ public class DefaultPluginManager } } - protected void addPlugin( Plugin plugin, - Artifact pluginArtifact, - MavenProject project, - ArtifactRepository localRepository ) - throws ArtifactNotFoundException, ArtifactResolutionException, PluginManagerException, - InvalidPluginException - { - // ---------------------------------------------------------------------------- - // Get the dependencies for the Plugin - // ---------------------------------------------------------------------------- - - // 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 = getPluginArtifacts( pluginArtifact, projectPlugin, project, localRepository ); - - addPlugin( plugin, projectPlugin, pluginArtifact, artifacts ); - } - protected void addPlugin( Plugin plugin, Artifact pluginArtifact, MavenProject project, @@ -373,24 +343,26 @@ public class DefaultPluginManager Set artifacts = getPluginArtifacts( pluginArtifact, projectPlugin, project, session.getLocalRepository() ); - addPlugin( plugin, projectPlugin, pluginArtifact, artifacts ); - } + String key = projectPlugin.getKey(); - private void addPlugin( Plugin plugin, - Plugin projectPlugin, - Artifact pluginArtifact, - Set artifacts ) - throws ArtifactNotFoundException, ArtifactResolutionException, PluginManagerException, - InvalidPluginException - { - // TODO When/if we go to project-level plugin instances (like for plugin-level deps in the - // POM), we need to undo this somehow. - ClassRealm pluginRealm = container.getComponentRealm( projectPlugin.getKey() ); + ClassRealm pluginRealm; + + // if we have a project session, it must mean we have extensions... + // which in turn may alter the execution of a plugin. + MavenProjectSession projectSession = session.getProjectSession( project ); + if ( projectSession != null ) + { + pluginRealm = projectSession.getComponentRealm( key ); + } + else + { + pluginRealm = container.getComponentRealm( key ); + } if ( ( pluginRealm != null ) && ( pluginRealm != container.getContainerRealm() ) ) { getLogger().debug( - "Realm already exists for: " + projectPlugin.getKey() + "Realm already exists for: " + key + ". Skipping addition..." ); // we've already discovered this plugin, and configured it, so skip it this time. @@ -405,22 +377,80 @@ public class DefaultPluginManager try { - List jars = new ArrayList(); - - for ( Iterator i = artifacts.iterator(); i.hasNext(); ) + if ( projectSession != null ) { - Artifact artifact = (Artifact) i.next(); + componentRealm = projectSession.createPluginRealm( projectPlugin ); - jars.add( artifact.getFile() ); + try + { + componentRealm.addURL( pluginArtifact.getFile().toURI().toURL() ); + } + catch ( MalformedURLException e ) + { + throw new PluginContainerException( plugin, componentRealm, "Error rendering plugin artifact: " + pluginArtifact.getId() + " as URL.", e ); + } + + for ( Iterator i = artifacts.iterator(); i.hasNext(); ) + { + Artifact artifact = (Artifact) i.next(); + + try + { + getLogger().debug( "Adding: " + artifact.getId() + " to plugin class-realm: " + key + " in project-session: " + project.getId() ); + componentRealm.addURL( artifact.getFile().toURI().toURL() ); + } + catch ( MalformedURLException e ) + { + throw new PluginContainerException( plugin, componentRealm, "Error rendering plugin artifact: " + artifact.getId() + " as URL.", e ); + } + } + + try + { + getLogger().debug( "Discovering components in realm: " + componentRealm ); + container.discoverComponents( componentRealm, false ); + } + catch ( PlexusConfigurationException e ) + { + throw new PluginContainerException( plugin, componentRealm, "Error re-scanning project realm for components.", e ); + } + catch ( ComponentRepositoryException e ) + { + throw new PluginContainerException( plugin, componentRealm, "Error re-scanning project realm for components.", e ); + } + } + else + { + List jars = new ArrayList(); + + for ( Iterator i = artifacts.iterator(); i.hasNext(); ) + { + Artifact artifact = (Artifact) i.next(); + + jars.add( artifact.getFile() ); + } + + jars.add( pluginArtifact.getFile() ); + + // Now here we need the artifact coreArtifactFilter stuff + componentRealm = container.createComponentRealm( key, jars ); } - jars.add( pluginArtifact.getFile() ); + } + catch ( PlexusContainerException e ) + { + throw new PluginContainerException( plugin, componentRealm, "Failed to create realm for plugin '" + projectPlugin + + ".", e ); + } + catch ( DuplicateRealmException e ) + { + throw new PluginContainerException( plugin, componentRealm, "Failed to create project-specific realm for plugin '" + projectPlugin + + " in project: " + project.getId(), e ); + } - // Now here we need the artifact coreArtifactFilter stuff - - componentRealm = container.createComponentRealm( projectPlugin.getKey(), jars ); - - String parentRealmId = componentRealm.getParentRealm().getId(); + try + { + String parentRealmId = container.getContainerRealm().getId(); // adding for MNG-3012 to try to work around problems with Xpp3Dom (from plexus-utils) // spawning a ClassCastException when a mojo calls plugin.getConfiguration() from maven-model... @@ -435,11 +465,6 @@ public class DefaultPluginManager // (maven-reporting-impl version 2.0; line 134; affects: checkstyle plugin, and probably others) componentRealm.importFrom( parentRealmId, "/default-report.xml" ); } - catch ( PlexusContainerException e ) - { - throw new PluginContainerException( plugin, componentRealm, "Failed to create realm for plugin '" + projectPlugin - + ".", e ); - } catch ( NoSuchRealmException e ) { throw new PluginContainerException( plugin, componentRealm, @@ -767,7 +792,24 @@ public class DefaultPluginManager Mojo plugin; - ClassRealm realm = mojoDescriptor.getPluginDescriptor().getClassRealm(); + ClassRealm realm = null; + + MavenProjectSession projectSession = session.getProjectSession( project ); + if ( projectSession != null ) + { + try + { + realm = projectSession.getPluginRealm( pluginDescriptor ); + } + catch ( NoSuchRealmException e ) + { + throw new PluginManagerException( mojoDescriptor, project, "Plugin realm: " + pluginDescriptor.getId() + " not found in project session for: " + project.getId(), e ); + } + } + else + { + realm = mojoDescriptor.getPluginDescriptor().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 @@ -1329,7 +1371,7 @@ public class DefaultPluginManager public void contextualize( Context context ) throws ContextException { - container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY ); + container = (MutablePlexusContainer) context.get( PlexusConstants.PLEXUS_KEY ); mojoLogger = new DefaultLog( container.getLoggerManager().getLoggerForComponent( Mojo.ROLE ) ); } diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginContainerException.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginContainerException.java index 07e1212d6b..ab5881711c 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/PluginContainerException.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginContainerException.java @@ -4,8 +4,13 @@ import org.apache.maven.model.Plugin; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.codehaus.plexus.PlexusContainerException; import org.codehaus.plexus.classworlds.realm.ClassRealm; +import org.codehaus.plexus.classworlds.realm.DuplicateRealmException; import org.codehaus.plexus.classworlds.realm.NoSuchRealmException; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.codehaus.plexus.component.repository.exception.ComponentRepositoryException; +import org.codehaus.plexus.configuration.PlexusConfigurationException; + +import java.net.MalformedURLException; /** * Exception which occurs to indicate that the plugin cannot be initialized due @@ -13,7 +18,7 @@ import org.codehaus.plexus.component.repository.exception.ComponentLookupExcepti * artifactId, and version for the plugin; at times, the goal name for which * execution failed; a message detailing the problem; the ClassRealm used to * lookup the plugin; and the Plexus exception that caused this error. - * + * * @author jdcasey * */ @@ -53,6 +58,46 @@ public class PluginContainerException this.pluginRealm = pluginRealm; } + public PluginContainerException( Plugin plugin, + ClassRealm pluginRealm, + String message, + DuplicateRealmException e ) + { + super( plugin, message, e ); + + this.pluginRealm = pluginRealm; + } + + public PluginContainerException( Plugin plugin, + ClassRealm pluginRealm, + String message, + MalformedURLException e ) + { + super( plugin, message, e ); + + this.pluginRealm = pluginRealm; + } + + public PluginContainerException( Plugin plugin, + ClassRealm pluginRealm, + String message, + PlexusConfigurationException e ) + { + super( plugin, message, e ); + + this.pluginRealm = pluginRealm; + } + + public PluginContainerException( Plugin plugin, + ClassRealm pluginRealm, + String message, + ComponentRepositoryException e ) + { + super( plugin, message, e ); + + this.pluginRealm = pluginRealm; + } + public ClassRealm getPluginRealm() { return pluginRealm; diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginManagerException.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginManagerException.java index d0d6121bb0..6a7b26b489 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/PluginManagerException.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginManagerException.java @@ -3,9 +3,15 @@ package org.apache.maven.plugin; import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; import org.apache.maven.model.Plugin; import org.apache.maven.plugin.descriptor.MojoDescriptor; +import org.apache.maven.project.MavenProject; import org.codehaus.plexus.PlexusContainerException; +import org.codehaus.plexus.classworlds.realm.DuplicateRealmException; import org.codehaus.plexus.classworlds.realm.NoSuchRealmException; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.codehaus.plexus.component.repository.exception.ComponentRepositoryException; +import org.codehaus.plexus.configuration.PlexusConfigurationException; + +import java.net.MalformedURLException; /* * Licensed to the Apache Software Foundation (ASF) under one @@ -44,6 +50,8 @@ public class PluginManagerException private String goal; + private MavenProject project; + protected PluginManagerException( Plugin plugin, String message, PlexusContainerException cause ) @@ -86,6 +94,64 @@ public class PluginManagerException pluginVersion = plugin.getVersion(); } + protected PluginManagerException( Plugin plugin, + String message, + DuplicateRealmException cause ) + { + super( message, cause ); + + pluginGroupId = plugin.getGroupId(); + pluginArtifactId = plugin.getArtifactId(); + pluginVersion = plugin.getVersion(); + } + + protected PluginManagerException( Plugin plugin, + String message, + MalformedURLException cause ) + { + super( message, cause ); + + pluginGroupId = plugin.getGroupId(); + pluginArtifactId = plugin.getArtifactId(); + pluginVersion = plugin.getVersion(); + } + + public PluginManagerException( Plugin plugin, + String message, + PlexusConfigurationException cause ) + { + super( message, cause ); + + pluginGroupId = plugin.getGroupId(); + pluginArtifactId = plugin.getArtifactId(); + pluginVersion = plugin.getVersion(); + } + + public PluginManagerException( Plugin plugin, + String message, + ComponentRepositoryException cause ) + { + super( message, cause ); + + pluginGroupId = plugin.getGroupId(); + pluginArtifactId = plugin.getArtifactId(); + pluginVersion = plugin.getVersion(); + } + + public PluginManagerException( MojoDescriptor mojoDescriptor, + MavenProject project, + String message, + NoSuchRealmException cause ) + { + super( message, cause ); + + this.project = project; + pluginGroupId = mojoDescriptor.getPluginDescriptor().getGroupId(); + pluginArtifactId = mojoDescriptor.getPluginDescriptor().getArtifactId(); + pluginVersion = mojoDescriptor.getPluginDescriptor().getVersion(); + goal = mojoDescriptor.getGoal(); + } + public String getPluginGroupId() { return pluginGroupId; @@ -105,4 +171,9 @@ public class PluginManagerException { return goal; } + + public MavenProject getProject() + { + return project; + } } diff --git a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java index 2666302cb1..d6c86b6f59 100644 --- a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java +++ b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java @@ -230,7 +230,7 @@ public class PluginParameterExpressionEvaluatorTest .setLocalRepository( repo ); return new MavenSession( container, request, new DefaultEventDispatcher(), - new ReactorManager( Collections.EMPTY_LIST, ReactorManager.FAIL_FAST ) ); + new ReactorManager( Collections.EMPTY_LIST, ReactorManager.FAIL_FAST ), Collections.EMPTY_MAP ); } public void testLocalRepositoryExtraction() diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml index cea3d0f997..9844b6673f 100644 --- a/maven-embedder/pom.xml +++ b/maven-embedder/pom.xml @@ -208,6 +208,40 @@ under the License. + + shade-maven-plugin + org.codehaus.mojo + 1.0-alpha-12 + + + package + + shade + + + + maven-embedder-std-2.1 + false + true + + + + + + org.codehaus.plexus.util + + org.codehaus.plexus.util.xml.Xpp3Dom + org.codehaus.plexus.util.xml.pull.* + + + + org.jdom + + + + + + maven-assembly-plugin 2.2-beta-1 diff --git a/maven-embedder/src/main/assembly/bin.xml b/maven-embedder/src/main/assembly/bin.xml index 2cffa6ce08..0bcbb7b12d 100644 --- a/maven-embedder/src/main/assembly/bin.xml +++ b/maven-embedder/src/main/assembly/bin.xml @@ -43,6 +43,7 @@ under the License. org.apache.maven:maven-artifact org.apache.maven:maven-monitor org.apache.maven:maven-plugin-descriptor + jdom:jdom @@ -81,7 +82,7 @@ under the License. target lib - maven*.jar + maven-embedder-std*.jar diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java index f770cbcfc4..cc67798401 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java @@ -92,52 +92,66 @@ public class CLIManager { options = new Options(); - options.addOption( OptionBuilder.hasArg( true ).create( ALTERNATE_POM_FILE ) ); + options.addOption( OptionBuilder.withLongOpt( "file" ).hasArg().withDescription( + "Force the use of an alternate POM file." ).create( ALTERNATE_POM_FILE ) ); options.addOption( - OptionBuilder.hasArg( true ).create( + OptionBuilder.withLongOpt( "define" ).hasArg().withDescription( "Define a system property" ).create( SET_SYSTEM_PROPERTY ) ); options.addOption( - OptionBuilder.create( OFFLINE ) ); + OptionBuilder.withLongOpt( "offline" ).withDescription( "Work offline" ).create( OFFLINE ) ); options.addOption( - OptionBuilder.create( HELP ) ); + OptionBuilder.withLongOpt( "help" ).withDescription( "Display help information" ).create( HELP ) ); options.addOption( - OptionBuilder.create( + OptionBuilder.withLongOpt( "version" ).withDescription( "Display version information" ).create( VERSION ) ); options.addOption( - OptionBuilder.create( + OptionBuilder.withLongOpt( "quiet" ).withDescription( "Quiet output - only show errors" ).create( QUIET ) ); options.addOption( - OptionBuilder.create( + OptionBuilder.withLongOpt( "debug" ).withDescription( "Produce execution debug output" ).create( DEBUG ) ); options.addOption( - OptionBuilder.create( + OptionBuilder.withLongOpt( "errors" ).withDescription( "Produce execution error messages" ).create( ERRORS ) ); - options.addOption( OptionBuilder.create( REACTOR ) ); - options.addOption( OptionBuilder.create( NON_RECURSIVE ) ); - options.addOption( OptionBuilder.create( UPDATE_SNAPSHOTS ) ); - options.addOption( OptionBuilder.hasArg( true ).create( ACTIVATE_PROFILES ) ); + options.addOption( OptionBuilder.withLongOpt( "reactor" ).withDescription( + "Execute goals for project found in the reactor" ).create( REACTOR ) ); + options.addOption( OptionBuilder.withLongOpt( "non-recursive" ).withDescription( + "Do not recurse into sub-projects" ).create( NON_RECURSIVE ) ); + options.addOption( OptionBuilder.withLongOpt( "update-snapshots" ).withDescription( + "Forces a check for updated releases and snapshots on remote repositories" ).create( UPDATE_SNAPSHOTS ) ); + options.addOption( OptionBuilder.withLongOpt( "activate-profiles" ).withDescription( + "Comma-delimited list of profiles to activate" ).hasArg().create( ACTIVATE_PROFILES ) ); - options.addOption( OptionBuilder.create( BATCH_MODE ) ); + options.addOption( OptionBuilder.withLongOpt( "batch-mode" ).withDescription( + "Run in non-interactive (batch) mode" ).create( BATCH_MODE ) ); - options.addOption( OptionBuilder.create( FORCE_PLUGIN_UPDATES ) ); - options.addOption( OptionBuilder.create( FORCE_PLUGIN_UPDATES2 ) ); - options.addOption( OptionBuilder.create( SUPPRESS_PLUGIN_UPDATES ) ); + options.addOption( OptionBuilder.withLongOpt( "check-plugin-updates" ).withDescription( + "Force upToDate check for any relevant registered plugins" ).create( FORCE_PLUGIN_UPDATES ) ); + options.addOption( OptionBuilder.withLongOpt( "update-plugins" ).withDescription( + "Synonym for " + FORCE_PLUGIN_UPDATES ).create( FORCE_PLUGIN_UPDATES2 ) ); + options.addOption( OptionBuilder.withLongOpt( "no-plugin-updates" ).withDescription( + "Suppress upToDate check for any relevant registered plugins" ).create( SUPPRESS_PLUGIN_UPDATES ) ); - options.addOption(OptionBuilder + options.addOption(OptionBuilder.withLongOpt("no-snapshot-updates") + .withDescription("Supress SNAPSHOT updates") .create(SUPRESS_SNAPSHOT_UPDATES)); - options.addOption( OptionBuilder.create( SUPPRESS_PLUGIN_REGISTRY ) ); + options.addOption( OptionBuilder.withLongOpt( "no-plugin-registry" ).withDescription( + "Don't use ~/.m2/plugin-registry.xml for plugin versions" ).create( SUPPRESS_PLUGIN_REGISTRY ) ); - options.addOption( OptionBuilder.create( CHECKSUM_FAILURE_POLICY ) ); + options.addOption( OptionBuilder.withLongOpt( "strict-checksums" ).withDescription( + "Fail the build if checksums don't match" ).create( CHECKSUM_FAILURE_POLICY ) ); options.addOption( - OptionBuilder.create( + OptionBuilder.withLongOpt( "lax-checksums" ).withDescription( "Warn if checksums don't match" ).create( CHECKSUM_WARNING_POLICY ) ); - options.addOption( OptionBuilder.hasArg( true ) + options.addOption( OptionBuilder.withLongOpt( "settings" ) + .withDescription( "Alternate path for the user settings file" ).hasArg() .create( ALTERNATE_USER_SETTINGS ) ); - options.addOption( OptionBuilder.create( FAIL_FAST ) ); + options.addOption( OptionBuilder.withLongOpt( "fail-fast" ).withDescription( + "Stop at first failure in reactorized builds" ).create( FAIL_FAST ) ); options.addOption( OptionBuilder.withLongOpt( "fail-at-end" ).withDescription( "Only fail the build afterwards; allow all non-impacted builds to continue" ).create( FAIL_AT_END ) ); diff --git a/maven-embedder/src/main/java/org/apache/maven/embedder/MavenEmbedder.java b/maven-embedder/src/main/java/org/apache/maven/embedder/MavenEmbedder.java index b457d61479..89e313f4fc 100644 --- a/maven-embedder/src/main/java/org/apache/maven/embedder/MavenEmbedder.java +++ b/maven-embedder/src/main/java/org/apache/maven/embedder/MavenEmbedder.java @@ -38,6 +38,8 @@ import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenExecutionResult; import org.apache.maven.execution.MavenSession; import org.apache.maven.execution.ReactorManager; +import org.apache.maven.extension.BuildExtensionScanner; +import org.apache.maven.extension.ExtensionScanningException; import org.apache.maven.lifecycle.LifecycleUtils; import org.apache.maven.model.Model; import org.apache.maven.model.Plugin; @@ -127,6 +129,8 @@ public class MavenEmbedder private MavenProjectBuilder mavenProjectBuilder; + private BuildExtensionScanner extensionScanner; + private MavenXpp3Reader modelReader; private MavenJDOMWriter modelWriter; @@ -323,7 +327,7 @@ public class MavenEmbedder { PluginManager pluginManager = (PluginManager) container.lookup( PluginManager.ROLE ); - MavenSession session = new MavenSession( container, request, null, null ); + MavenSession session = new MavenSession( container, request, null, null, new HashMap() ); pluginManager.verifyPlugin( plugin, project, session ); } @@ -428,8 +432,12 @@ public class MavenEmbedder // ---------------------------------------------------------------------- public MavenProject readProject( File mavenProject ) - throws ProjectBuildingException + throws ProjectBuildingException, ExtensionScanningException { + getLogger().info( "Scanning for extensions: " + mavenProject ); + extensionScanner.scanForBuildExtensions( mavenProject, request.getLocalRepository(), request.getProfileManager(), new HashMap() ); + + getLogger().info( "Building MavenProject instance: " + mavenProject ); return mavenProjectBuilder.build( mavenProject, request.getLocalRepository(), request.getProfileManager() ); } @@ -474,8 +482,12 @@ public class MavenEmbedder { return result.addProjectBuildingException( e ); } + catch ( ExtensionScanningException e ) + { + return result.addExtensionScanningException( e ); + } - ReactorManager reactorManager = maven.createReactorManager( request, result ); + ReactorManager reactorManager = maven.createReactorManager( request, result, new HashMap() ); if ( result.hasExceptions() ) { @@ -673,6 +685,8 @@ public class MavenEmbedder mavenProjectBuilder = (MavenProjectBuilder) container.lookup( MavenProjectBuilder.ROLE ); + extensionScanner = (BuildExtensionScanner) container.lookup( BuildExtensionScanner.ROLE ); + // ---------------------------------------------------------------------- // Artifact related components // ----------------------------------------------------------------------