From 4d6343267903aab6a415e716f3b426305215b95e Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 10 Mar 2022 14:34:49 +0100 Subject: [PATCH 1/5] [MNG-7402] Make sure the top level project classloader is used throughout the build --- .../apache/maven/lifecycle/internal/LifecycleStarter.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java index 834498126080..40571b9e5a3f 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java @@ -29,6 +29,7 @@ import org.apache.maven.lifecycle.MissingProjectException; import org.apache.maven.lifecycle.NoGoalSpecifiedException; import org.apache.maven.lifecycle.internal.builder.Builder; +import org.apache.maven.lifecycle.internal.builder.BuilderCommon; import org.apache.maven.lifecycle.internal.builder.BuilderNotFoundException; import org.apache.maven.session.scope.internal.SessionScope; import org.codehaus.plexus.component.annotations.Component; @@ -77,8 +78,11 @@ public void execute( MavenSession session ) ProjectBuildList projectBuilds = null; MavenExecutionResult result = session.getResult(); + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); try { + BuilderCommon.attachToThread( session.getTopLevelProject() ); + if ( buildExecutionRequiresProject( session ) && projectIsNotPresent( session ) ) { throw new MissingProjectException( "The goal you specified requires a project to execute" @@ -134,6 +138,7 @@ public void execute( MavenSession session ) finally { eventCatapult.fire( ExecutionEvent.Type.SessionEnded, session, null ); + Thread.currentThread().setContextClassLoader( tccl ); } } From d86c27635c8c520690c8b22393a3ff5aa4428744 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 10 Mar 2022 16:36:32 +0100 Subject: [PATCH 2/5] Revert "[MNG-7402] BuildListCalculator never detaches the classloader" This reverts commit d29af9018b5c80177102aaab96bd37ed5fedf26c. --- .../lifecycle/internal/BuildListCalculator.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java index 4fef69b4a9c7..76454f810d47 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java @@ -57,18 +57,10 @@ public ProjectBuildList calculateProjectBuilds( MavenSession session, List Date: Fri, 11 Mar 2022 14:41:59 +0100 Subject: [PATCH 3/5] Clean up class loaders usage --- .../internal/BuildListCalculator.java | 2 -- .../lifecycle/internal/ExecutionPlanItem.java | 3 --- .../internal/LifecycleModuleBuilder.java | 19 +++++++++++++++---- .../lifecycle/internal/LifecycleStarter.java | 4 +--- .../lifecycle/internal/ReactorContext.java | 10 +--------- 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java index 76454f810d47..fc5521f6540b 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java @@ -20,7 +20,6 @@ */ import org.apache.maven.execution.MavenSession; -import org.apache.maven.lifecycle.internal.builder.BuilderCommon; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.component.annotations.Component; @@ -57,7 +56,6 @@ public ProjectBuildList calculateProjectBuilds( MavenSession session, List createExecutionPlanItems( MavenProject mavenProject, List executions ) { - BuilderCommon.attachToThread( mavenProject ); - List result = new ArrayList<>(); for ( MojoExecution mojoExecution : executions ) { diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java index 1cbaf5334606..8f167dc00094 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java @@ -83,6 +83,21 @@ public void buildProject( MavenSession session, ReactorContext reactorContext, M public void buildProject( MavenSession session, MavenSession rootSession, ReactorContext reactorContext, MavenProject currentProject, TaskSegment taskSegment ) + { + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + try + { + BuilderCommon.attachToThread( currentProject ); + doBuildProject( session, rootSession, reactorContext, currentProject, taskSegment ); + } + finally + { + Thread.currentThread().setContextClassLoader( tccl ); + } + } + + private void doBuildProject( MavenSession session, MavenSession rootSession, ReactorContext reactorContext, + MavenProject currentProject, TaskSegment taskSegment ) { session.setCurrentProject( currentProject ); @@ -105,8 +120,6 @@ public void buildProject( MavenSession session, MavenSession rootSession, Reacto return; } - BuilderCommon.attachToThread( currentProject ); - projectExecutionListener.beforeProjectExecution( new ProjectExecutionEvent( session, currentProject ) ); eventCatapult.fire( ExecutionEvent.Type.ProjectStarted, session, null ); @@ -155,8 +168,6 @@ public void buildProject( MavenSession session, MavenSession rootSession, Reacto } session.setCurrentProject( null ); - - Thread.currentThread().setContextClassLoader( reactorContext.getOriginalContextClassLoader() ); } } } diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java index 40571b9e5a3f..37c246d5cb88 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java @@ -108,10 +108,8 @@ public void execute( MavenSession session ) lifecycleDebugLogger.debugReactorPlan( projectBuilds ); } - ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader(); ReactorBuildStatus reactorBuildStatus = new ReactorBuildStatus( session.getProjectDependencyGraph() ); - reactorContext = - new ReactorContext( result, projectIndex, oldContextClassLoader, reactorBuildStatus ); + reactorContext = new ReactorContext( result, projectIndex, reactorBuildStatus ); String builderId = session.getRequest().getBuilderId(); Builder builder = builders.get( builderId ); diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorContext.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorContext.java index 076c6229f8ef..d045766626ec 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorContext.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorContext.java @@ -35,16 +35,13 @@ public class ReactorContext private final ProjectIndex projectIndex; - private final ClassLoader originalContextClassLoader; - private final ReactorBuildStatus reactorBuildStatus; public ReactorContext( MavenExecutionResult result, ProjectIndex projectIndex, - ClassLoader originalContextClassLoader, ReactorBuildStatus reactorBuildStatus ) + ReactorBuildStatus reactorBuildStatus ) { this.result = result; this.projectIndex = projectIndex; - this.originalContextClassLoader = originalContextClassLoader; this.reactorBuildStatus = reactorBuildStatus; } @@ -63,9 +60,4 @@ public ProjectIndex getProjectIndex() return projectIndex; } - public ClassLoader getOriginalContextClassLoader() - { - return originalContextClassLoader; - } - } From 1cf1b9ec21bf1fa20605a478d7e46a908ea33c27 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 11 Mar 2022 14:48:34 +0100 Subject: [PATCH 4/5] Fix the lookup for the MojosExecutionStrategy so that it can look into the session scope --- .../lifecycle/internal/MojoExecutor.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java index f81c71376d19..8a6d08739cda 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java @@ -19,6 +19,11 @@ * under the License. */ +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; + import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.resolver.filter.ArtifactFilter; import org.apache.maven.artifact.resolver.filter.CumulativeScopeArtifactFilter; @@ -38,8 +43,6 @@ import org.apache.maven.plugin.PluginManagerException; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.util.StringUtils; import org.eclipse.aether.SessionData; @@ -69,26 +72,27 @@ * @author Kristian Rosenvold * @since 3.0 */ -@Component( role = MojoExecutor.class ) +@Named +@Singleton public class MojoExecutor { - @Requirement + @Inject private BuildPluginManager pluginManager; - @Requirement + @Inject private MavenPluginManager mavenPluginManager; - @Requirement + @Inject private LifecycleDependencyResolver lifeCycleDependencyResolver; - @Requirement + @Inject private ExecutionEventCatapult eventCatapult; private final ReadWriteLock aggregatorLock = new ReentrantReadWriteLock(); - @Requirement - private MojosExecutionStrategy mojosExecutionStrategy; + @Inject + private Provider mojosExecutionStrategy; public MojoExecutor() { @@ -159,7 +163,9 @@ public void execute( final MavenSession session, final PhaseRecorder phaseRecorder = new PhaseRecorder( session.getCurrentProject() ); - mojosExecutionStrategy.execute( mojoExecutions, session, new MojoExecutionRunner() + final MojosExecutionStrategy strategy = mojosExecutionStrategy.get(); + + strategy.execute( mojoExecutions, session, new MojoExecutionRunner() { @Override public void run( MojoExecution mojoExecution ) throws LifecycleExecutionException From aef51692b9cecb3bf8dbd9eb4fc84016729d7c0e Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 11 Mar 2022 19:47:35 +0100 Subject: [PATCH 5/5] Handle build extensions with a single ClassRealm --- .../java/org/apache/maven/DefaultMaven.java | 159 +++++++++--------- .../internal/LifecycleModuleBuilder.java | 15 -- .../lifecycle/internal/LifecycleStarter.java | 5 - 3 files changed, 82 insertions(+), 97 deletions(-) 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 7447b8ca5640..3d33b0a71b20 100644 --- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java +++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java @@ -23,9 +23,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Date; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -51,6 +49,8 @@ import org.apache.maven.repository.LocalRepositoryNotAccessibleException; import org.apache.maven.session.scope.internal.SessionScope; import org.codehaus.plexus.PlexusContainer; +import org.codehaus.plexus.classworlds.realm.ClassRealm; +import org.codehaus.plexus.classworlds.realm.DuplicateRealmException; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; @@ -202,12 +202,7 @@ private MavenExecutionResult doExecute( MavenExecutionRequest request, MavenSess { try { - // CHECKSTYLE_OFF: LineLength - for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( Collections.emptyList() ) ) - { - listener.afterSessionStart( session ); - } - // CHECKSTYLE_ON: LineLength + callListeners( session, AbstractMavenLifecycleParticipant::afterSessionStart ); } catch ( MavenExecutionException e ) { @@ -232,6 +227,32 @@ private MavenExecutionResult doExecute( MavenExecutionRequest request, MavenSess return addExceptionToResult( result, e ); } + + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + try + { + ClassRealm lookupRealm = setupBuildExtensions( session ); + Thread.currentThread().setContextClassLoader( lookupRealm ); + container.setLookupRealm( lookupRealm ); + + return doExecute2( request, result, session, repoSession ); + } + catch ( DuplicateRealmException e ) + { + return addExceptionToResult( result, e ); + } + finally + { + Thread.currentThread().setContextClassLoader( tccl ); + } + } + + private MavenExecutionResult doExecute2( MavenExecutionRequest request, + MavenExecutionResult result, + MavenSession session, + DefaultRepositorySystemSession repoSession ) + { + Result graphResult; try { setupWorkspaceReader( session, repoSession ); @@ -243,24 +264,14 @@ private MavenExecutionResult doExecute( MavenExecutionRequest request, MavenSess repoSession.setReadOnly(); - ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); try { - for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( session.getProjects() ) ) - { - Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() ); - - listener.afterProjectsRead( session ); - } + callListeners( session, AbstractMavenLifecycleParticipant::afterProjectsRead ); } catch ( MavenExecutionException e ) { return addExceptionToResult( result, e ); } - finally - { - Thread.currentThread().setContextClassLoader( originalClassLoader ); - } // // The projects need to be topologically after the participants have run their afterProjectsRead(session) @@ -313,10 +324,59 @@ private MavenExecutionResult doExecute( MavenExecutionRequest request, MavenSess return addExceptionToResult( result, e ); } } - return result; } + @FunctionalInterface + interface ListenerMethod + { + void run( AbstractMavenLifecycleParticipant listener, MavenSession session ) throws MavenExecutionException; + } + + private void callListeners( MavenSession session, ListenerMethod method ) throws MavenExecutionException + { + ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); + try + { + for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( session.getProjects() ) ) + { + Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() ); + + method.run( listener, session ); + } + } + finally + { + Thread.currentThread().setContextClassLoader( originalClassLoader ); + } + } + + private ClassRealm setupBuildExtensions( MavenSession session ) throws DuplicateRealmException + { + List buildExtensionsRealms = new ArrayList<>(); + for ( MavenProject project : session.getProjects() ) + { + ClassRealm realm = project.getClassRealm(); + if ( realm != null ) + { + buildExtensionsRealms.add( realm ); + } + } + if ( !buildExtensionsRealms.isEmpty() ) + { + ClassRealm extRealm = container.createChildRealm( "session.ext" ); + for ( ClassRealm realm : buildExtensionsRealms ) + { + extRealm.importFrom( realm, realm.getId() ); + } + return extRealm; + } + else + { + return container.getContainerRealm(); + } + } + private void setupWorkspaceReader( MavenSession session, DefaultRepositorySystemSession repoSession ) throws ComponentLookupException { @@ -331,8 +391,7 @@ private void setupWorkspaceReader( MavenSession session, DefaultRepositorySystem workspaceReaders.add( repoWorkspaceReader ); } // 3) .. n) Project-scoped workspace readers - for ( WorkspaceReader workspaceReader : getProjectScopedExtensionComponents( session.getProjects(), - WorkspaceReader.class ) ) + for ( WorkspaceReader workspaceReader : container.lookupList( WorkspaceReader.class ) ) { if ( workspaceReaders.contains( workspaceReader ) ) { @@ -342,26 +401,12 @@ private void setupWorkspaceReader( MavenSession session, DefaultRepositorySystem } WorkspaceReader[] readers = workspaceReaders.toArray( new WorkspaceReader[0] ); repoSession.setWorkspaceReader( new ChainedWorkspaceReader( readers ) ); - } private void afterSessionEnd( Collection projects, MavenSession session ) throws MavenExecutionException { - ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); - try - { - for ( AbstractMavenLifecycleParticipant listener : getLifecycleParticipants( projects ) ) - { - Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() ); - - listener.afterSessionEnd( session ); - } - } - finally - { - Thread.currentThread().setContextClassLoader( originalClassLoader ); - } + callListeners( session, AbstractMavenLifecycleParticipant::afterSessionEnd ); } public RepositorySystemSession newRepositorySession( MavenExecutionRequest request ) @@ -398,49 +443,9 @@ private Collection getLifecycleParticipants( logger.warn( "Failed to lookup lifecycle participants: " + e.getMessage() ); } - lifecycleListeners.addAll( getProjectScopedExtensionComponents( projects, - AbstractMavenLifecycleParticipant.class ) ); - return lifecycleListeners; } - protected Collection getProjectScopedExtensionComponents( Collection projects, Class role ) - { - - Collection foundComponents = new LinkedHashSet<>(); - Collection scannedRealms = new HashSet<>(); - - Thread currentThread = Thread.currentThread(); - ClassLoader originalContextClassLoader = currentThread.getContextClassLoader(); - try - { - for ( MavenProject project : projects ) - { - ClassLoader projectRealm = project.getClassRealm(); - - if ( projectRealm != null && scannedRealms.add( projectRealm ) ) - { - currentThread.setContextClassLoader( projectRealm ); - - try - { - foundComponents.addAll( container.lookupList( role ) ); - } - catch ( ComponentLookupException e ) - { - // this is just silly, lookupList should return an empty list! - logger.warn( "Failed to lookup " + role + ": " + e.getMessage() ); - } - } - } - return foundComponents; - } - finally - { - currentThread.setContextClassLoader( originalContextClassLoader ); - } - } - private MavenExecutionResult addExceptionToResult( MavenExecutionResult result, Throwable e ) { if ( !result.getExceptions().contains( e ) ) diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java index 8f167dc00094..68baa0b0d088 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java @@ -83,21 +83,6 @@ public void buildProject( MavenSession session, ReactorContext reactorContext, M public void buildProject( MavenSession session, MavenSession rootSession, ReactorContext reactorContext, MavenProject currentProject, TaskSegment taskSegment ) - { - ClassLoader tccl = Thread.currentThread().getContextClassLoader(); - try - { - BuilderCommon.attachToThread( currentProject ); - doBuildProject( session, rootSession, reactorContext, currentProject, taskSegment ); - } - finally - { - Thread.currentThread().setContextClassLoader( tccl ); - } - } - - private void doBuildProject( MavenSession session, MavenSession rootSession, ReactorContext reactorContext, - MavenProject currentProject, TaskSegment taskSegment ) { session.setCurrentProject( currentProject ); diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java index 37c246d5cb88..46af74e46a0d 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java @@ -29,7 +29,6 @@ import org.apache.maven.lifecycle.MissingProjectException; import org.apache.maven.lifecycle.NoGoalSpecifiedException; import org.apache.maven.lifecycle.internal.builder.Builder; -import org.apache.maven.lifecycle.internal.builder.BuilderCommon; import org.apache.maven.lifecycle.internal.builder.BuilderNotFoundException; import org.apache.maven.session.scope.internal.SessionScope; import org.codehaus.plexus.component.annotations.Component; @@ -78,11 +77,8 @@ public void execute( MavenSession session ) ProjectBuildList projectBuilds = null; MavenExecutionResult result = session.getResult(); - ClassLoader tccl = Thread.currentThread().getContextClassLoader(); try { - BuilderCommon.attachToThread( session.getTopLevelProject() ); - if ( buildExecutionRequiresProject( session ) && projectIsNotPresent( session ) ) { throw new MissingProjectException( "The goal you specified requires a project to execute" @@ -136,7 +132,6 @@ public void execute( MavenSession session ) finally { eventCatapult.fire( ExecutionEvent.Type.SessionEnded, session, null ); - Thread.currentThread().setContextClassLoader( tccl ); } }