Updated Branches: refs/heads/master 07fecbd9e -> b99658c94
MNG-5549 introduced MojoExecutionListener and ProjectExecutionListener Signed-off-by: Igor Fedorenko <ifedore...@apache.org> Project: http://git-wip-us.apache.org/repos/asf/maven/repo Commit: http://git-wip-us.apache.org/repos/asf/maven/commit/bc84e6c7 Tree: http://git-wip-us.apache.org/repos/asf/maven/tree/bc84e6c7 Diff: http://git-wip-us.apache.org/repos/asf/maven/diff/bc84e6c7 Branch: refs/heads/master Commit: bc84e6c7d307f119d82d5ae8082cc5e4f7eb7996 Parents: 07fecbd Author: Igor Fedorenko <ifedore...@apache.org> Authored: Sat Dec 14 19:43:42 2013 -0500 Committer: Igor Fedorenko <ifedore...@apache.org> Committed: Sat Dec 14 19:43:42 2013 -0500 ---------------------------------------------------------------------- .../maven/execution/MojoExecutionListener.java | 46 +++++++ .../execution/ProjectExecutionListener.java | 49 +++++++ .../execution/scope/MojoExecutionListener.java | 48 ------- .../scope/WeakMojoExecutionListener.java | 50 ++++++++ .../scope/internal/MojoExecutionScope.java | 36 ++++-- .../CompoundProjectExecutionListener.java | 76 +++++++++++ .../internal/LifecycleModuleBuilder.java | 34 ++++- .../plugin/CompoundMojoExecutionListener.java | 67 ++++++++++ .../maven/plugin/DefaultBuildPluginManager.java | 33 ++++- .../DelegatingMojoExecutionListener.java | 61 +++++++++ .../DelegatingProjectExecutionListener.java | 66 ++++++++++ .../maven/lifecycle/LifecycleExecutorTest.java | 127 +++++++++++++++++++ 12 files changed, 626 insertions(+), 67 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/maven/blob/bc84e6c7/maven-core/src/main/java/org/apache/maven/execution/MojoExecutionListener.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/execution/MojoExecutionListener.java b/maven-core/src/main/java/org/apache/maven/execution/MojoExecutionListener.java new file mode 100644 index 0000000..6b824eb --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/execution/MojoExecutionListener.java @@ -0,0 +1,46 @@ +package org.apache.maven.execution; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.execution.scope.WeakMojoExecutionListener; +import org.apache.maven.plugin.Mojo; +import org.apache.maven.plugin.MojoExecution; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; + +/** + * Extension point that allows build extensions observe and possibly veto mojo executions. + * + * @see WeakMojoExecutionListener + * @since 3.1.2 + * @provisional This interface is part of work in progress and can be changed or removed without notice. + */ +public interface MojoExecutionListener +{ + public void beforeMojoExecution( MavenSession session, MavenProject project, MojoExecution execution, Mojo mojo ) + throws MojoExecutionException; + + public void afterMojoExecutionSuccess( MavenSession session, MavenProject project, MojoExecution execution, + Mojo mojo ) + throws MojoExecutionException; + + public void afterExecutionFailure( MavenSession session, MavenProject project, MojoExecution execution, Mojo mojo, + Throwable cause ); +} http://git-wip-us.apache.org/repos/asf/maven/blob/bc84e6c7/maven-core/src/main/java/org/apache/maven/execution/ProjectExecutionListener.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/execution/ProjectExecutionListener.java b/maven-core/src/main/java/org/apache/maven/execution/ProjectExecutionListener.java new file mode 100644 index 0000000..d3d9739 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/execution/ProjectExecutionListener.java @@ -0,0 +1,49 @@ +package org.apache.maven.execution; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.List; + +import org.apache.maven.lifecycle.LifecycleExecutionException; +import org.apache.maven.plugin.MojoExecution; +import org.apache.maven.project.MavenProject; + +/** + * Extension point that allows build extensions observe and possibly veto project build execution. + * + * @see ExecutionListener + * @see MojoExecutionListener + * @since 3.1.2 + * @provisional This interface is part of work in progress and can be changed or removed without notice. + */ +public interface ProjectExecutionListener +{ + public void beforeProjectExecution( MavenSession session, MavenProject project ) + throws LifecycleExecutionException; + + public void beforeProjectLifecycleExecution( MavenSession session, MavenProject project, + List<MojoExecution> executionPlan ) + throws LifecycleExecutionException; + + public void afterProjectExecutionSuccess( MavenSession session, MavenProject project ) + throws LifecycleExecutionException; + + public void afterProjectExecutionFailure( MavenSession session, MavenProject project, Throwable cause ); +} http://git-wip-us.apache.org/repos/asf/maven/blob/bc84e6c7/maven-core/src/main/java/org/apache/maven/execution/scope/MojoExecutionListener.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/execution/scope/MojoExecutionListener.java b/maven-core/src/main/java/org/apache/maven/execution/scope/MojoExecutionListener.java deleted file mode 100644 index 7a9c84b..0000000 --- a/maven-core/src/main/java/org/apache/maven/execution/scope/MojoExecutionListener.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.apache.maven.execution.scope; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import org.apache.maven.plugin.MojoExecutionException; - -/** - * Helper interface that allows mojo execution scoped components to be notified before execution start and after - * execution completion. The main purpose of this interface is to allow mojo execution scoped components perform setup - * before and cleanup after mojo execution. - * <p> - * TODO decide if Mojo should be passed as parameter of callback methods - * - * @author igor - * @since 3.1.2 - * @provisional This interface is part of work in progress and can be changed or removed without notice. - */ -public interface MojoExecutionListener -{ - // TODO decide if this is needed - // public void beforeExecution() throws MojoExecutionException; - - public void afterMojoExecutionSuccess() - throws MojoExecutionException; - - // TODO decide if this is needed. - // public void afterExecutionFailure(Throwable t) throws MojoExecutionException; - - public void afterMojoExecutionAlways() - throws MojoExecutionException; -} http://git-wip-us.apache.org/repos/asf/maven/blob/bc84e6c7/maven-core/src/main/java/org/apache/maven/execution/scope/WeakMojoExecutionListener.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/execution/scope/WeakMojoExecutionListener.java b/maven-core/src/main/java/org/apache/maven/execution/scope/WeakMojoExecutionListener.java new file mode 100644 index 0000000..5537106 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/execution/scope/WeakMojoExecutionListener.java @@ -0,0 +1,50 @@ +package org.apache.maven.execution.scope; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.execution.MojoExecutionListener; +import org.apache.maven.plugin.Mojo; +import org.apache.maven.plugin.MojoExecution; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; + +/** + * Extension point that allows build extensions observe and possibly veto mojo executions. + * <p> + * Unlike {@link MojoExecutionListener}, this extension point does not trigger instantiation of the component, hence + * "weak" class name prefix. Only applies to mojo execution scoped components. + * + * @see MojoExecutionListener + * @since 3.1.2 + * @provisional This interface is part of work in progress and can be changed or removed without notice. + */ +public interface WeakMojoExecutionListener +{ + public void beforeMojoExecution( MavenSession session, MavenProject project, MojoExecution execution, Mojo mojo ) + throws MojoExecutionException; + + public void afterMojoExecutionSuccess( MavenSession session, MavenProject project, MojoExecution execution, + Mojo mojo ) + throws MojoExecutionException; + + public void afterExecutionFailure( MavenSession session, MavenProject project, MojoExecution execution, Mojo mojo, + Throwable cause ); +} http://git-wip-us.apache.org/repos/asf/maven/blob/bc84e6c7/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScope.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScope.java b/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScope.java index ce169e1..80badfc 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScope.java +++ b/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScope.java @@ -26,8 +26,10 @@ import javax.inject.Named; import javax.inject.Singleton; import org.apache.maven.execution.MavenSession; -import org.apache.maven.execution.scope.MojoExecutionListener; +import org.apache.maven.execution.MojoExecutionListener; import org.apache.maven.execution.scope.MojoExecutionScoped; +import org.apache.maven.execution.scope.WeakMojoExecutionListener; +import org.apache.maven.plugin.Mojo; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; @@ -46,7 +48,7 @@ import com.google.inject.util.Providers; @Named @Singleton public class MojoExecutionScope - implements Scope + implements Scope, MojoExecutionListener { private static final Provider<Object> SEEDED_KEY_PROVIDER = new Provider<Object>() { @@ -138,7 +140,7 @@ public class MojoExecutionScope } T provided = (T) state.provided.get( key ); - if ( provided == null ) + if ( provided == null && unscoped != null ) { provided = unscoped.get(); state.provided.put( key, provided ); @@ -174,28 +176,40 @@ public class MojoExecutionScope }; } - public void afterExecutionSuccess() + public void beforeMojoExecution( MavenSession session, MavenProject project, MojoExecution execution, Mojo mojo ) throws MojoExecutionException { for ( Object provided : getScopeState().provided.values() ) { - if ( provided instanceof MojoExecutionListener ) + if ( provided instanceof WeakMojoExecutionListener ) { - ( (MojoExecutionListener) provided ).afterMojoExecutionSuccess(); - // TODO maybe deal with multiple MojoExecutionExceptions + ( (WeakMojoExecutionListener) provided ).beforeMojoExecution( session, project, execution, mojo ); } } } - public void afterExecutionAlways() + public void afterMojoExecutionSuccess( MavenSession session, MavenProject project, MojoExecution execution, + Mojo mojo ) throws MojoExecutionException { for ( Object provided : getScopeState().provided.values() ) { - if ( provided instanceof MojoExecutionListener ) + if ( provided instanceof WeakMojoExecutionListener ) { - ( (MojoExecutionListener) provided ).afterMojoExecutionAlways(); - // TODO maybe deal with multiple MojoExecutionExceptions + ( (WeakMojoExecutionListener) provided ).afterMojoExecutionSuccess( session, project, execution, mojo ); + } + } + } + + public void afterExecutionFailure( MavenSession session, MavenProject project, MojoExecution execution, Mojo mojo, + Throwable cause ) + { + for ( Object provided : getScopeState().provided.values() ) + { + if ( provided instanceof WeakMojoExecutionListener ) + { + ( (WeakMojoExecutionListener) provided ).afterExecutionFailure( session, project, execution, mojo, + cause ); } } } http://git-wip-us.apache.org/repos/asf/maven/blob/bc84e6c7/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CompoundProjectExecutionListener.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CompoundProjectExecutionListener.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CompoundProjectExecutionListener.java new file mode 100644 index 0000000..8bdd210 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CompoundProjectExecutionListener.java @@ -0,0 +1,76 @@ +package org.apache.maven.lifecycle.internal; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Collection; +import java.util.List; + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.execution.ProjectExecutionListener; +import org.apache.maven.lifecycle.LifecycleExecutionException; +import org.apache.maven.plugin.MojoExecution; +import org.apache.maven.project.MavenProject; + +class CompoundProjectExecutionListener + implements ProjectExecutionListener +{ + private final Collection<ProjectExecutionListener> listeners; + + public CompoundProjectExecutionListener( Collection<ProjectExecutionListener> listeners ) + { + this.listeners = listeners; // NB this is live injected collection + } + + public void beforeProjectExecution( MavenSession session, MavenProject project ) + throws LifecycleExecutionException + { + for ( ProjectExecutionListener listener : listeners ) + { + listener.beforeProjectExecution( session, project ); + } + } + + public void beforeProjectLifecycleExecution( MavenSession session, MavenProject project, + List<MojoExecution> executionPlan ) + throws LifecycleExecutionException + { + for ( ProjectExecutionListener listener : listeners ) + { + listener.beforeProjectLifecycleExecution( session, project, executionPlan ); + } + } + + public void afterProjectExecutionSuccess( MavenSession session, MavenProject project ) + throws LifecycleExecutionException + { + for ( ProjectExecutionListener listener : listeners ) + { + listener.afterProjectExecutionSuccess( session, project ); + } + } + + public void afterProjectExecutionFailure( MavenSession session, MavenProject project, Throwable cause ) + { + for ( ProjectExecutionListener listener : listeners ) + { + listener.afterProjectExecutionFailure( session, project, cause ); + } + } +} http://git-wip-us.apache.org/repos/asf/maven/blob/bc84e6c7/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java ---------------------------------------------------------------------- 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 c8a3cf4..95f1c19 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 @@ -19,20 +19,23 @@ package org.apache.maven.lifecycle.internal; * under the License. */ +import java.util.HashSet; +import java.util.List; + import org.apache.maven.artifact.Artifact; import org.apache.maven.execution.BuildSuccess; import org.apache.maven.execution.ExecutionEvent; import org.apache.maven.execution.MavenSession; +import org.apache.maven.execution.ProjectExecutionListener; import org.apache.maven.lifecycle.MavenExecutionPlan; +import org.apache.maven.plugin.MojoExecution; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; -import java.util.HashSet; - /** * Builds one or more lifecycles for a full module - * + * * @since 3.0 * @author Benjamin Bentmann * @author Jason van Zyl @@ -53,6 +56,18 @@ public class LifecycleModuleBuilder @Requirement private ExecutionEventCatapult eventCatapult; + private ProjectExecutionListener projectExecutionListener; + + // this tricks plexus-component-metadata generate required metadata + @Requirement + private List<ProjectExecutionListener> projectExecutionListeners; + + public void setProjectExecutionListeners( final List<ProjectExecutionListener> listeners ) + { + this.projectExecutionListeners = listeners; + this.projectExecutionListener = new CompoundProjectExecutionListener( listeners ); + } + public void buildProject( MavenSession session, ReactorContext reactorContext, MavenProject currentProject, TaskSegment taskSegment ) { @@ -75,16 +90,23 @@ public class LifecycleModuleBuilder return; } + BuilderCommon.attachToThread( currentProject ); + + projectExecutionListener.beforeProjectExecution( rootSession, currentProject ); + eventCatapult.fire( ExecutionEvent.Type.ProjectStarted, session, null ); - BuilderCommon.attachToThread( currentProject ); MavenExecutionPlan executionPlan = builderCommon.resolveBuildPlan( session, currentProject, taskSegment, new HashSet<Artifact>() ); + List<MojoExecution> mojoExecutions = executionPlan.getMojoExecutions(); - mojoExecutor.execute( session, executionPlan.getMojoExecutions(), reactorContext.getProjectIndex() ); + projectExecutionListener.beforeProjectLifecycleExecution( rootSession, currentProject, mojoExecutions ); + mojoExecutor.execute( session, mojoExecutions, reactorContext.getProjectIndex() ); long buildEndTime = System.currentTimeMillis(); + projectExecutionListener.afterProjectExecutionSuccess( rootSession, currentProject ); + reactorContext.getResult().addBuildSummary( new BuildSuccess( currentProject, buildEndTime - buildStartTime ) ); @@ -93,6 +115,8 @@ public class LifecycleModuleBuilder catch ( Exception e ) { builderCommon.handleBuildError( reactorContext, rootSession, session, currentProject, e, buildStartTime ); + + projectExecutionListener.afterProjectExecutionFailure( session, currentProject, e ); } finally { http://git-wip-us.apache.org/repos/asf/maven/blob/bc84e6c7/maven-core/src/main/java/org/apache/maven/plugin/CompoundMojoExecutionListener.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/plugin/CompoundMojoExecutionListener.java b/maven-core/src/main/java/org/apache/maven/plugin/CompoundMojoExecutionListener.java new file mode 100644 index 0000000..7b5ff66 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/plugin/CompoundMojoExecutionListener.java @@ -0,0 +1,67 @@ +package org.apache.maven.plugin; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Collection; + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.execution.MojoExecutionListener; +import org.apache.maven.project.MavenProject; + +class CompoundMojoExecutionListener + implements MojoExecutionListener +{ + + private final Collection<MojoExecutionListener> listeners; + + public CompoundMojoExecutionListener( Collection<MojoExecutionListener> listeners ) + { + this.listeners = listeners; // NB this is live injected collection + } + + public void beforeMojoExecution( MavenSession session, MavenProject project, MojoExecution execution, Mojo mojo ) + throws MojoExecutionException + { + for ( MojoExecutionListener listener : listeners ) + { + listener.beforeMojoExecution( session, project, execution, mojo ); + } + } + + public void afterMojoExecutionSuccess( MavenSession session, MavenProject project, MojoExecution execution, + Mojo mojo ) + throws MojoExecutionException + { + for ( MojoExecutionListener listener : listeners ) + { + listener.afterMojoExecutionSuccess( session, project, execution, mojo ); + } + } + + public void afterExecutionFailure( MavenSession session, MavenProject project, MojoExecution execution, Mojo mojo, + Throwable cause ) + { + for ( MojoExecutionListener listener : listeners ) + { + listener.afterExecutionFailure( session, project, execution, mojo, cause ); + } + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/bc84e6c7/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java ---------------------------------------------------------------------- diff --git a/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java index 949a228..5a10053 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java @@ -24,6 +24,7 @@ import java.io.PrintStream; import java.util.List; import org.apache.maven.execution.MavenSession; +import org.apache.maven.execution.MojoExecutionListener; import org.apache.maven.execution.scope.internal.MojoExecutionScope; import org.apache.maven.model.Plugin; import org.apache.maven.plugin.descriptor.MojoDescriptor; @@ -52,6 +53,18 @@ public class DefaultBuildPluginManager @Requirement private MojoExecutionScope scope; + private MojoExecutionListener mojoExecutionListener; + + // this tricks plexus-component-metadata generate required metadata + @Requirement( role = MojoExecutionListener.class ) + private List<MojoExecutionListener> mojoExecutionListeners; + + public void setMojoExecutionListeners( final List<MojoExecutionListener> listeners ) + { + this.mojoExecutionListeners = listeners; + this.mojoExecutionListener = new CompoundMojoExecutionListener( listeners ); + } + /** * @param plugin * @param repositories @@ -112,9 +125,11 @@ public class DefaultBuildPluginManager // MavenProjectHelper.attachArtifact(..). try { + mojoExecutionListener.beforeMojoExecution( oldSession, project, mojoExecution, mojo ); + mojo.execute(); - scope.afterExecutionSuccess(); + mojoExecutionListener.afterMojoExecutionSuccess( oldSession, project, mojoExecution, mojo ); } catch ( ClassCastException e ) { @@ -128,10 +143,14 @@ public class DefaultBuildPluginManager } catch ( PluginContainerException e ) { + mojoExecutionListener.afterExecutionFailure( oldSession, project, mojoExecution, mojo, e ); + throw new PluginExecutionException( mojoExecution, project, e ); } catch ( NoClassDefFoundError e ) { + mojoExecutionListener.afterExecutionFailure( oldSession, project, mojoExecution, mojo, e ); + ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 ); PrintStream ps = new PrintStream( os ); ps.println( "A required class was missing while executing " + mojoDescriptor.getId() + ": " @@ -144,6 +163,8 @@ public class DefaultBuildPluginManager } catch ( LinkageError e ) { + mojoExecutionListener.afterExecutionFailure( oldSession, project, mojoExecution, mojo, e ); + ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 ); PrintStream ps = new PrintStream( os ); ps.println( "An API incompatibility was encountered while executing " + mojoDescriptor.getId() + ": " @@ -156,6 +177,8 @@ public class DefaultBuildPluginManager } catch ( ClassCastException e ) { + mojoExecutionListener.afterExecutionFailure( oldSession, project, mojoExecution, mojo, e ); + ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 ); PrintStream ps = new PrintStream( os ); ps.println( "A type incompatibility occured while executing " + mojoDescriptor.getId() + ": " @@ -164,10 +187,14 @@ public class DefaultBuildPluginManager throw new PluginExecutionException( mojoExecution, project, os.toString(), e ); } - finally + catch ( RuntimeException e ) { - scope.afterExecutionAlways(); + mojoExecutionListener.afterExecutionFailure( oldSession, project, mojoExecution, mojo, e ); + throw e; + } + finally + { mavenPluginManager.releaseMojo( mojo, mojoExecution ); scope.exit(); http://git-wip-us.apache.org/repos/asf/maven/blob/bc84e6c7/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingMojoExecutionListener.java ---------------------------------------------------------------------- diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingMojoExecutionListener.java b/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingMojoExecutionListener.java new file mode 100644 index 0000000..d58329c --- /dev/null +++ b/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingMojoExecutionListener.java @@ -0,0 +1,61 @@ +package org.apache.maven.lifecycle; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.execution.MojoExecutionListener; +import org.apache.maven.plugin.Mojo; +import org.apache.maven.plugin.MojoExecution; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; + +@Named +@Singleton +public class DelegatingMojoExecutionListener + implements MojoExecutionListener +{ + private final List<MojoExecutionListener> listeners = new CopyOnWriteArrayList<MojoExecutionListener>(); + + public void beforeMojoExecution( MavenSession session, MavenProject project, MojoExecution execution, Mojo mojo ) + throws MojoExecutionException + { + for ( MojoExecutionListener listener : listeners ) + { + listener.beforeMojoExecution( session, project, execution, mojo ); + } + } + + public void afterMojoExecutionSuccess( MavenSession session, MavenProject project, MojoExecution execution, + Mojo mojo ) + throws MojoExecutionException + { + for ( MojoExecutionListener listener : listeners ) + { + listener.afterMojoExecutionSuccess( session, project, execution, mojo ); + } + } + + public void afterExecutionFailure( MavenSession session, MavenProject project, MojoExecution execution, Mojo mojo, + Throwable cause ) + { + for ( MojoExecutionListener listener : listeners ) + { + listener.afterExecutionFailure( session, project, execution, mojo, cause ); + } + } + + public void addMojoExecutionListener( MojoExecutionListener listener ) + { + this.listeners.add( listener ); + } + + public void removeMojoExecutionListener( MojoExecutionListener listener ) + { + this.listeners.remove( listener ); + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/bc84e6c7/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingProjectExecutionListener.java ---------------------------------------------------------------------- diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingProjectExecutionListener.java b/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingProjectExecutionListener.java new file mode 100644 index 0000000..27b53c6 --- /dev/null +++ b/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingProjectExecutionListener.java @@ -0,0 +1,66 @@ +package org.apache.maven.lifecycle; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.execution.ProjectExecutionListener; +import org.apache.maven.plugin.MojoExecution; +import org.apache.maven.project.MavenProject; + +@Named +@Singleton +public class DelegatingProjectExecutionListener + implements ProjectExecutionListener +{ + private final List<ProjectExecutionListener> listeners = new CopyOnWriteArrayList<ProjectExecutionListener>(); + + public void beforeProjectExecution( MavenSession session, MavenProject project ) + throws LifecycleExecutionException + { + for ( ProjectExecutionListener listener : listeners ) + { + listener.beforeProjectExecution( session, project ); + } + } + + public void beforeProjectLifecycleExecution( MavenSession session, MavenProject project, + List<MojoExecution> executionPlan ) + throws LifecycleExecutionException + { + for ( ProjectExecutionListener listener : listeners ) + { + listener.beforeProjectLifecycleExecution( session, project, executionPlan ); + } + } + + public void afterProjectExecutionSuccess( MavenSession session, MavenProject project ) + throws LifecycleExecutionException + { + for ( ProjectExecutionListener listener : listeners ) + { + listener.afterProjectExecutionSuccess( session, project ); + } + } + + public void afterProjectExecutionFailure( MavenSession session, MavenProject project, Throwable cause ) + { + for ( ProjectExecutionListener listener : listeners ) + { + listener.afterProjectExecutionFailure( session, project, cause ); + } + } + + public void addProjectExecutionListener( ProjectExecutionListener listener ) + { + this.listeners.add( listener ); + } + + public void removeProjectExecutionListener( ProjectExecutionListener listener ) + { + this.listeners.remove( listener ); + } +} http://git-wip-us.apache.org/repos/asf/maven/blob/bc84e6c7/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java ---------------------------------------------------------------------- diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java index 82e7e93..b983e55 100644 --- a/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java +++ b/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java @@ -18,11 +18,15 @@ package org.apache.maven.lifecycle; import java.io.File; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.apache.maven.AbstractCoreMavenComponentTestCase; import org.apache.maven.exception.ExceptionHandler; import org.apache.maven.execution.MavenSession; +import org.apache.maven.execution.MojoExecutionListener; +import org.apache.maven.execution.ProjectDependencyGraph; +import org.apache.maven.execution.ProjectExecutionListener; import org.apache.maven.lifecycle.internal.DefaultLifecycleTaskSegmentCalculator; import org.apache.maven.lifecycle.internal.ExecutionPlanItem; import org.apache.maven.lifecycle.internal.LifecycleExecutionPlanCalculator; @@ -31,9 +35,12 @@ import org.apache.maven.lifecycle.internal.LifecycleTaskSegmentCalculator; import org.apache.maven.lifecycle.internal.MojoDescriptorCreator; import org.apache.maven.lifecycle.internal.TaskSegment; import org.apache.maven.model.Plugin; +import org.apache.maven.plugin.Mojo; import org.apache.maven.plugin.MojoExecution; +import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoNotFoundException; import org.apache.maven.plugin.descriptor.MojoDescriptor; +import org.apache.maven.project.MavenProject; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.util.xml.Xpp3Dom; @@ -380,4 +387,124 @@ public class LifecycleExecutorTest assertEquals("1.0", execution.getConfiguration().getChild( "version" ).getAttribute( "default-value" )); } + public void testExecutionListeners() + throws Exception + { + final File pom = getProject( "project-basic" ); + final MavenSession session = createMavenSession( pom ); + session.setProjectDependencyGraph( new ProjectDependencyGraph() + { + public List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive ) + { + return Collections.emptyList(); + } + + public List<MavenProject> getSortedProjects() + { + return Collections.singletonList( session.getCurrentProject() ); + } + + public List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive ) + { + return Collections.emptyList(); + } + } ); + + final List<String> log = new ArrayList<String>(); + + MojoExecutionListener mojoListener = new MojoExecutionListener() + { + public void beforeMojoExecution( MavenSession session, MavenProject project, MojoExecution execution, + Mojo mojo ) + throws MojoExecutionException + { + log.add( "beforeMojoExecution " + project.getArtifactId() + ":" + execution.getExecutionId() ); + } + + public void afterMojoExecutionSuccess( MavenSession session, MavenProject project, MojoExecution execution, + Mojo mojo ) + throws MojoExecutionException + { + log.add( "afterMojoExecutionSuccess " + project.getArtifactId() + ":" + execution.getExecutionId() ); + } + + public void afterExecutionFailure( MavenSession session, MavenProject project, MojoExecution execution, + Mojo mojo, Throwable cause ) + { + log.add( "afterExecutionFailure " + project.getArtifactId() + ":" + execution.getExecutionId() ); + } + }; + ProjectExecutionListener projectListener = new ProjectExecutionListener() + { + public void beforeProjectExecution( MavenSession session, MavenProject project ) + throws LifecycleExecutionException + { + log.add( "beforeProjectExecution " + project.getArtifactId() ); + } + + public void beforeProjectLifecycleExecution( MavenSession session, MavenProject project, + List<MojoExecution> executionPlan ) + throws LifecycleExecutionException + { + log.add( "beforeProjectLifecycleExecution " + project.getArtifactId() ); + } + + public void afterProjectExecutionSuccess( MavenSession session, MavenProject project ) + throws LifecycleExecutionException + { + log.add( "afterProjectExecutionSuccess " + project.getArtifactId() ); + } + + public void afterProjectExecutionFailure( MavenSession session, MavenProject project, Throwable cause ) + { + log.add( "afterProjectExecutionFailure " + project.getArtifactId() ); + } + }; + lookup( DelegatingProjectExecutionListener.class ).addProjectExecutionListener( projectListener ); + lookup( DelegatingMojoExecutionListener.class ).addMojoExecutionListener( mojoListener ); + + try + { + lifecycleExecutor.execute( session ); + } + finally + { + lookup( DelegatingProjectExecutionListener.class ).removeProjectExecutionListener( projectListener ); + lookup( DelegatingMojoExecutionListener.class ).removeMojoExecutionListener( mojoListener ); + } + + List<String> expectedLog = Arrays.asList( "beforeProjectExecution project-basic", // + "beforeProjectLifecycleExecution project-basic", // + "beforeMojoExecution project-basic:default-resources", // + "afterMojoExecutionSuccess project-basic:default-resources", // + "beforeMojoExecution project-basic:default-compile", // + "afterMojoExecutionSuccess project-basic:default-compile", // + "beforeMojoExecution project-basic:default-testResources", // + "afterMojoExecutionSuccess project-basic:default-testResources", // + "beforeMojoExecution project-basic:default-testCompile", // + "afterMojoExecutionSuccess project-basic:default-testCompile", // + "beforeMojoExecution project-basic:default-test", // + "afterMojoExecutionSuccess project-basic:default-test", // + "beforeMojoExecution project-basic:default-jar", // + "afterMojoExecutionSuccess project-basic:default-jar", // + "afterProjectExecutionSuccess project-basic" // + ); + + assertEventLog( expectedLog, log ); + } + + private static void assertEventLog( List<String> expectedList, List<String> actualList ) + { + assertEquals( toString( expectedList ), toString( actualList ) ); + } + + private static String toString( List<String> lines ) + { + StringBuilder sb = new StringBuilder(); + for ( String line : lines ) + { + sb.append( line ).append( '\n' ); + } + return sb.toString(); + } }