diff --git a/README.txt b/README.txt
deleted file mode 100644
index df3dd45..0000000
--- a/README.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-See: 
-
-http://maven.apache.org/guides/development/guide-building-m2.html
-
diff --git a/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java b/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java
index 135b3e8..d1e7643 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java
@@ -25,11 +25,8 @@ import java.util.List;
 import java.util.Set;
 
 import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.*;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
-import org.apache.maven.lifecycle.LifecycleExecutor;
-import org.apache.maven.lifecycle.LifecycleNotFoundException;
-import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
-import org.apache.maven.lifecycle.MavenExecutionPlan;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.PluginExecution;
 import org.apache.maven.plugin.InvalidPluginDescriptorException;
@@ -55,7 +52,7 @@ public class EmptyLifecycleExecutor
         throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
         MojoNotFoundException
     {
-        return new MavenExecutionPlan( Collections.<MojoExecution> emptyList(), null, null );
+        return new MavenExecutionPlan(null, null, null );
     }
 
     public void execute( MavenSession session )
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 807d41d..573ffb1 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -237,7 +237,7 @@ public class DefaultMaven
         // Reactor
         // Workspace
         // User Local Repository
-        delegatingLocalArtifactRepository.setBuildReactor( new ReactorArtifactRepository( projectMap, session ) );
+        delegatingLocalArtifactRepository.setBuildReactor( new ReactorArtifactRepository( projectMap, session, request ) );
         
         if ( result.hasExceptions() )
         {
diff --git a/maven-core/src/main/java/org/apache/maven/ReactorArtifactRepository.java b/maven-core/src/main/java/org/apache/maven/ReactorArtifactRepository.java
index dedde22..b9d3345 100644
--- a/maven-core/src/main/java/org/apache/maven/ReactorArtifactRepository.java
+++ b/maven-core/src/main/java/org/apache/maven/ReactorArtifactRepository.java
@@ -11,9 +11,12 @@ import java.util.Map;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.execution.BuildSuccess;
+import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenExecutionResult;
 import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuildingRequest;
 import org.apache.maven.repository.LocalArtifactRepository;
 
 /**
@@ -32,11 +35,14 @@ public class ReactorArtifactRepository
 
     private MavenExecutionResult executionResult;
 
+    private final MavenExecutionRequest mavenExecutionRequest;
+
     private final int hashCode;
 
-    public ReactorArtifactRepository( Map<String, MavenProject> reactorProjects, MavenSession session )
+    public ReactorArtifactRepository( Map<String, MavenProject> reactorProjects, MavenSession session, MavenExecutionRequest mavenExecutionRequest )
     {
         this.reactorProjects = reactorProjects;
+        this.mavenExecutionRequest = mavenExecutionRequest;
         this.executionResult = ( session != null ) ? session.getResult() : null;
         hashCode = ( reactorProjects != null ) ? reactorProjects.keySet().hashCode() : 0;
 
@@ -74,9 +80,11 @@ public class ReactorArtifactRepository
             {
                 //TODO Need to look for plugins
 
+                boolean isWeave =  mavenExecutionRequest.getWeaveConfiguration() != null;
+
                 Artifact projectArtifact = findMatchingArtifact( project, artifact );
 
-                if ( projectArtifact != null && projectArtifact.getFile() != null && projectArtifact.getFile().exists() )
+                if ( !isWeave && (projectArtifact != null && projectArtifact.getFile() != null && projectArtifact.getFile().exists()) )
                 {
                     //TODO: This is really completely wrong and should probably be based on the phase that is currently being executed.
                     // If we are running before the packaging phase there is going to be no archive anyway, but if we are running prior to package
@@ -84,7 +92,7 @@ public class ReactorArtifactRepository
 
                     resolve( artifact, projectArtifact.getFile() );
                 }
-                else if ( isProjectOutputValid( project ) )
+                else if ( isWeave ||  isProjectOutputValid( project ) )
                 {
                     File classesDir;
 
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/DefaultRepositoryRequest.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/DefaultRepositoryRequest.java
index 51d663e..189c6eb 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/DefaultRepositoryRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/repository/DefaultRepositoryRequest.java
@@ -22,6 +22,8 @@ package org.apache.maven.artifact.repository;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
 import org.apache.maven.repository.ArtifactTransferListener;
 
 /**
@@ -68,6 +70,21 @@ public class DefaultRepositoryRequest
         setTransferListener( repositoryRequest.getTransferListener() );
     }
 
+    public static RepositoryRequest getRepositoryRequest(MavenSession session, MavenProject project) {
+        RepositoryRequest request = new DefaultRepositoryRequest();
+
+        request.setCache(session.getRepositoryCache());
+        request.setLocalRepository(session.getLocalRepository());
+        if (project != null) {
+            request.setRemoteRepositories(project.getPluginArtifactRepositories());
+        }
+        request.setOffline(session.isOffline());
+        request.setForceUpdate(session.getRequest().isUpdateSnapshots());
+        request.setTransferListener(session.getRequest().getTransferListener());
+
+        return request;
+    }
+
     public boolean isOffline()
     {
         return offline;
diff --git a/maven-core/src/main/java/org/apache/maven/exception/DefaultExceptionHandler.java b/maven-core/src/main/java/org/apache/maven/exception/DefaultExceptionHandler.java
index 12f9d24..821079a 100644
--- a/maven-core/src/main/java/org/apache/maven/exception/DefaultExceptionHandler.java
+++ b/maven-core/src/main/java/org/apache/maven/exception/DefaultExceptionHandler.java
@@ -201,7 +201,7 @@ public class DefaultExceptionHandler
                     reference = exception.getClass().getSimpleName();
                 }
             }
-            else if ( exception instanceof LifecycleExecutionException )
+            else if ( exception instanceof LifecycleExecutionException)
             {
                 reference = getReference( exception.getCause() );
             }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java
index 937cc8e..a493961 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java
@@ -126,6 +126,8 @@ public class DefaultMavenExecutionRequest
 
     private ExecutionListener executionListener;
 
+    private String weaveConfiguration;
+
     /**
      * Suppress SNAPSHOT updates.
      *
@@ -1024,4 +1026,15 @@ public class DefaultMavenExecutionRequest
         return this;
     }
 
+    public String getWeaveConfiguration() {
+        return weaveConfiguration;
+    }
+
+    public void setWeaveConfiguration(String weaveConfiguration) {
+        this.weaveConfiguration = weaveConfiguration;
+    }
+
+    public boolean isWeave() {
+        return getWeaveConfiguration() != null;
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java
index 2ac483e..63265f7 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java
@@ -152,6 +152,10 @@ public interface MavenExecutionRequest
     MavenExecutionRequest setMakeBehavior( String makeBehavior );
     String getMakeBehavior();
 
+    void setWeaveConfiguration( String weaveConfiguration );
+    String getWeaveConfiguration();
+    boolean isWeave();
+
     // Recursive (really to just process the top-level POM)
     MavenExecutionRequest setRecursive( boolean recursive );
     boolean isRecursive();
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 2e26a21..3383bbd 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
@@ -20,14 +20,7 @@ package org.apache.maven.execution;
  */
 
 import java.io.File;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
+import java.util.*;
 
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.RepositoryCache;
@@ -43,7 +36,7 @@ import org.codehaus.plexus.component.repository.exception.ComponentLookupExcepti
  * @author Jason van Zyl
  * @version $Id$
  */
-public class MavenSession
+public class MavenSession implements Cloneable
 {
     private PlexusContainer container;
     
@@ -69,6 +62,8 @@ public class MavenSession
 
     private Collection<String> blackListedProjects;
 
+    private volatile boolean halted = false;
+
     @Deprecated
     public MavenSession( PlexusContainer container, MavenExecutionRequest request, MavenExecutionResult result, MavenProject project )
     {
@@ -314,6 +309,11 @@ public class MavenSession
         return pluginContext;
     }
 
+    public ProjectDependencyGraph getProjectDependencyGraph()
+    {
+        return projectDependencyGraph;
+    }
+
     public void setProjectDependencyGraph( ProjectDependencyGraph projectDependencyGraph )
     {
         this.projectDependencyGraph = projectDependencyGraph;
@@ -333,7 +333,7 @@ public class MavenSession
     {
         if ( blackListedProjects == null )
         {
-            blackListedProjects = new HashSet<String>();
+            blackListedProjects = Collections.synchronizedSet(new HashSet<String>());
         }
 
         if ( blackListedProjects.add( getId( project ) ) && projectDependencyGraph != null )
@@ -345,6 +345,19 @@ public class MavenSession
         }
     }
 
+    @Override
+    public MavenSession clone()
+    {
+        try
+        {
+            return (MavenSession) super.clone();
+        }
+        catch ( CloneNotSupportedException e )
+        {
+            throw new RuntimeException( "Bug", e );
+        }
+    }
+
     private String getId( MavenProject project )
     {
         return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion();
@@ -361,4 +374,14 @@ public class MavenSession
         return request.getStartTime();
     }
 
+        public void halt()
+    {
+        halted = true;
+    }
+
+    public boolean isHalted()
+    {
+        return halted;
+    }
+
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java
index 73c6d24..7d4db19 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java
@@ -1,1971 +1,185 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
  * agreements. See the NOTICE file distributed with this work for additional information regarding
  * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance with the License. You may obtain a
  * copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software distributed under the License
  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.TreeMap;
-import java.util.TreeSet;
+package org.apache.maven.lifecycle;
 
-import org.apache.maven.ProjectDependenciesResolver;
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.ArtifactUtils;
-import org.apache.maven.artifact.repository.DefaultRepositoryRequest;
-import org.apache.maven.artifact.repository.RepositoryRequest;
-import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
-import org.apache.maven.artifact.resolver.ArtifactResolutionException;
-import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
-import org.apache.maven.execution.BuildFailure;
-import org.apache.maven.execution.BuildSuccess;
-import org.apache.maven.execution.DefaultLifecycleEvent;
-import org.apache.maven.execution.ExecutionEvent;
-import org.apache.maven.execution.ExecutionListener;
-import org.apache.maven.execution.MavenExecutionRequest;
-import org.apache.maven.execution.MavenExecutionResult;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.lifecycle.mapping.LifecycleMapping;
-import org.apache.maven.model.Dependency;
+import org.apache.maven.execution.*;
+import org.apache.maven.lifecycle.internal.*;
 import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginExecution;
-import org.apache.maven.plugin.InvalidPluginDescriptorException;
 import org.apache.maven.plugin.MojoExecution;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugin.MojoNotFoundException;
-import org.apache.maven.plugin.PluginConfigurationException;
-import org.apache.maven.plugin.PluginDescriptorParsingException;
-import org.apache.maven.plugin.BuildPluginManager;
-import org.apache.maven.plugin.PluginManagerException;
-import org.apache.maven.plugin.PluginNotFoundException;
-import org.apache.maven.plugin.PluginResolutionException;
-import org.apache.maven.plugin.descriptor.MojoDescriptor;
-import org.apache.maven.plugin.descriptor.Parameter;
-import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.apache.maven.plugin.lifecycle.Execution;
-import org.apache.maven.plugin.lifecycle.Phase;
-import org.apache.maven.plugin.prefix.DefaultPluginPrefixRequest;
-import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
-import org.apache.maven.plugin.prefix.PluginPrefixRequest;
-import org.apache.maven.plugin.prefix.PluginPrefixResolver;
-import org.apache.maven.plugin.prefix.PluginPrefixResult;
-import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
-import org.apache.maven.plugin.version.PluginVersionRequest;
-import org.apache.maven.plugin.version.PluginVersionResolutionException;
-import org.apache.maven.plugin.version.PluginVersionResolver;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.repository.RepositorySystem;
-import org.codehaus.plexus.classworlds.realm.ClassRealm;
 import org.codehaus.plexus.component.annotations.Requirement;
-import org.codehaus.plexus.configuration.PlexusConfiguration;
 import org.codehaus.plexus.logging.Logger;
-import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
-import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 
-//TODO: The configuration for the lifecycle needs to be externalized so that I can use the annotations properly for the wiring and reference and external source for the lifecycle configuration.
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
 //TODO: check for online status in the build plan and die if necessary
 
 /**
  * @author Jason van Zyl
+ * @author Kristian Rosenvold
  */
 public class DefaultLifecycleExecutor
-    implements LifecycleExecutor, Initializable
-{
+        implements LifecycleExecutor {
     @Requirement
-    private Logger logger;
-
+    private LifeCyclePluginAnalyzer lifeCyclePluginAnalyzer;
     @Requirement
-    private BuildPluginManager pluginManager;
-
+    private DefaultLifecycles defaultLifeCycles;
     @Requirement
-    protected RepositorySystem repositorySystem;
-
+    private Logger logger;
     @Requirement
-    private ProjectDependenciesResolver projectDependenciesResolver;
-
+    private LifecycleModuleBuilder lifeCycleBuilder;
     @Requirement
-    private PluginVersionResolver pluginVersionResolver;
-
+    private LifecycleWeaveBuilder lifeCycleWeaveBuilder;
     @Requirement
-    private PluginPrefixResolver pluginPrefixResolver;
-            
-    // @Configuration(source="org/apache/maven/lifecycle/lifecycles.xml")    
-    private List<Lifecycle> lifecycles;
-
-    /**
-     * We use this to display all the lifecycles available and their phases to users. Currently this is primarily
-     * used in the IDE integrations where a UI is presented to the user and they can select the lifecycle phase
-     * they would like to execute.
-     */
-    private Map<String,Lifecycle> lifecycleMap;
-    
-    /**
-     * We use this to map all phases to the lifecycle that contains it. This is used so that a user can specify the 
-     * phase they want to execute and we can easily determine what lifecycle we need to run.
-     */
-    private Map<String, Lifecycle> phaseToLifecycleMap;
-
-    /**
-     * These mappings correspond to packaging types, like WAR packaging, which configure a particular mojos
-     * to run in a given phase.
-     */
+    private BuildListCalculator buildListCalculator;
     @Requirement
-    private Map<String, LifecycleMapping> lifecycleMappings;
-
-    private void fireEvent( MavenSession session, MojoExecution mojoExecution, LifecycleEventCatapult catapult )
-    {
-        ExecutionListener listener = session.getRequest().getExecutionListener();
-
-        if ( listener != null )
-        {
-            ExecutionEvent event = new DefaultLifecycleEvent( session, mojoExecution );
-
-            catapult.fire( listener, event );
-        }
-    }
-
-    private static String getKey( MavenProject project )
-    {
-        return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion();
-    }
-
-    private void debugReactorPlan( List<ProjectBuild> projectBuilds )
-    {
-        logger.debug( "=== REACTOR BUILD PLAN ================================================" );
-
-        for ( Iterator<ProjectBuild> it = projectBuilds.iterator(); it.hasNext(); )
-        {
-            ProjectBuild projectBuild = it.next();
-
-            logger.debug( "Project: " + projectBuild.project.getId() );
-            logger.debug( "Tasks:   " + projectBuild.taskSegment.tasks );
-            logger.debug( "Style:   " + ( projectBuild.taskSegment.aggregating ? "Aggregating" : "Regular" ) );
+    private LifecycleDebugLogger lifecycleDebugLogger;
 
-            if ( it.hasNext() )
-            {
-                logger.debug( "-----------------------------------------------------------------------" );
-            }
-        }
-
-        logger.debug( "=======================================================================" );
-    }
-
-    private void debugProjectPlan( MavenProject currentProject, MavenExecutionPlan executionPlan )
-    {
-        logger.debug( "=== PROJECT BUILD PLAN ================================================" );
-        logger.debug( "Project:       " + getKey( currentProject ) );
-        logger.debug( "Dependencies (collect): " + executionPlan.getRequiredCollectionScopes() );
-        logger.debug( "Dependencies (resolve): " + executionPlan.getRequiredResolutionScopes() );
-
-        for ( MojoExecution mojoExecution : executionPlan.getExecutions() )
-        {
-            debugMojoExecution( mojoExecution );
-        }
-
-        logger.debug( "=======================================================================" );
-    }
-
-    private void debugMojoExecution( MojoExecution mojoExecution )
-    {
-        String mojoExecId =
-            mojoExecution.getGroupId() + ':' + mojoExecution.getArtifactId() + ':' + mojoExecution.getVersion() + ':'
-                + mojoExecution.getGoal() + " (" + mojoExecution.getExecutionId() + ')';
-
-        Map<String, List<MojoExecution>> forkedExecutions = mojoExecution.getForkedExecutions();
-        if ( !forkedExecutions.isEmpty() )
-        {
-            for ( Map.Entry<String, List<MojoExecution>> fork : forkedExecutions.entrySet() )
-            {
-                logger.debug( "--- init fork of " + fork.getKey() + " for " + mojoExecId + " ---" );
-
-                for ( MojoExecution forkedExecution : fork.getValue() )
-                {
-                    debugMojoExecution( forkedExecution );
-                }
-
-                logger.debug( "--- exit fork of " + fork.getKey() + " for " + mojoExecId + " ---" );
-            }
-        }
-
-        logger.debug( "-----------------------------------------------------------------------" );
-        logger.debug( "Goal:          " + mojoExecId );
-        logger.debug( "Style:         "
-            + ( mojoExecution.getMojoDescriptor().isAggregating() ? "Aggregating" : "Regular" ) );
-        logger.debug( "Configuration: " + mojoExecution.getConfiguration() );
+    public DefaultLifecycleExecutor() {
     }
 
-    public void execute( MavenSession session )
-    {
-        fireEvent( session, null, LifecycleEventCatapult.SESSION_STARTED );
+    public void execute(MavenSession session) {
+        fireEvent(session, null, LifecycleEventCatapult.SESSION_STARTED);
 
         MavenExecutionResult result = session.getResult();
 
-        List<ProjectBuild> projectBuilds;
-
-        ProjectIndex projectIndex;
-
-        try
-        {
-            projectBuilds = calculateProjectBuilds( session );
-
-            projectIndex = new ProjectIndex( session.getProjects() );
-        }
-        catch ( Exception e )
-        {
-            result.addException( e );
-
-            fireEvent( session, null, LifecycleEventCatapult.SESSION_ENDED );
-
-            return;
-        }
-
-        if ( logger.isDebugEnabled() )
-        {
-            debugReactorPlan( projectBuilds );
-        }
-
-        ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
-
-        for ( ProjectBuild projectBuild : projectBuilds )
-        {
-            MavenProject currentProject = projectBuild.project;
-
-            long buildStartTime = System.currentTimeMillis();
-
-            try
-            {
-                session.setCurrentProject( currentProject );
-
-                if ( session.isBlackListed( currentProject ) )
-                {
-                    fireEvent( session, null, LifecycleEventCatapult.PROJECT_SKIPPED );
-
-                    continue;
-                }
-
-                fireEvent( session, null, LifecycleEventCatapult.PROJECT_STARTED );
-
-                ClassRealm projectRealm = currentProject.getClassRealm();
-                if ( projectRealm != null )
-                {
-                    Thread.currentThread().setContextClassLoader( projectRealm );
-                }
+        try {
+            ProjectBuildList projectBuilds = buildListCalculator.calculateProjectBuilds(session);
+            final MavenExecutionRequest executionRequest = session.getRequest();
+            boolean isWeave = executionRequest.isWeave();
 
-                MavenExecutionPlan executionPlan =
-                    calculateExecutionPlan( session, currentProject, projectBuild.taskSegment );
+            ProjectIndex projectIndex = new ProjectIndex(session.getProjects());
 
-                if ( logger.isDebugEnabled() )
-                {
-                    debugProjectPlan( currentProject, executionPlan );
-                }
-
-                // TODO: once we have calculated the build plan then we should accurately be able to download
-                // the project dependencies. Having it happen in the plugin manager is a tangled mess. We can optimize
-                // this later by looking at the build plan. Would be better to just batch download everything required
-                // by the reactor.
-
-                List<MavenProject> projectsToResolve;
-
-                if ( projectBuild.taskSegment.aggregating )
-                {
-                    projectsToResolve = session.getProjects();
-                }
-                else
-                {
-                    projectsToResolve = Collections.singletonList( currentProject );
-                }
-
-                for ( MavenProject project : projectsToResolve )
-                {
-                    resolveProjectDependencies( project, executionPlan.getRequiredCollectionScopes(),
-                                                executionPlan.getRequiredResolutionScopes(), session,
-                                                projectBuild.taskSegment.aggregating );
-                }
-
-                DependencyContext dependencyContext =
-                    new DependencyContext( executionPlan, projectBuild.taskSegment.aggregating );
-
-                for ( MojoExecution mojoExecution : executionPlan.getExecutions() )
-                {
-                    execute( session, mojoExecution, projectIndex, dependencyContext );
-                }
-
-                long buildEndTime = System.currentTimeMillis();
-
-                result.addBuildSummary( new BuildSuccess( currentProject, buildEndTime - buildStartTime ) );
-
-                fireEvent( session, null, LifecycleEventCatapult.PROJECT_SUCCEEDED );
-            }
-            catch ( Exception e )
-            {
-                result.addException( e );
-
-                long buildEndTime = System.currentTimeMillis();
-
-                result.addBuildSummary( new BuildFailure( currentProject, buildEndTime - buildStartTime, e ) );
-
-                fireEvent( session, null, LifecycleEventCatapult.PROJECT_FAILED );
-
-                if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( session.getReactorFailureBehavior() ) )
-                {
-                    // continue the build
-                }
-                else if ( MavenExecutionRequest.REACTOR_FAIL_AT_END.equals( session.getReactorFailureBehavior() ) )
-                {
-                    // continue the build but ban all projects that depend on the failed one
-                    session.blackList( currentProject );
-                }
-                else if ( MavenExecutionRequest.REACTOR_FAIL_FAST.equals( session.getReactorFailureBehavior() ) )
-                {
-                    // abort the build
-                    break;
-                }
-                else
-                {
-                    throw new IllegalArgumentException( "invalid reactor failure behavior "
-                        + session.getReactorFailureBehavior() );
-                }
+            if (logger.isDebugEnabled()) {
+                lifecycleDebugLogger.debugReactorPlan(projectBuilds);
             }
-            finally
-            {
-                session.setCurrentProject( null );
-
-                Thread.currentThread().setContextClassLoader( oldContextClassLoader );
-            }
-        }
-
-        fireEvent( session, null, LifecycleEventCatapult.SESSION_ENDED );
-    }
 
-    private void resolveProjectDependencies( MavenProject project, Collection<String> scopesToCollect,
-                                             Collection<String> scopesToResolve, MavenSession session,
-                                             boolean aggregating )
-        throws LifecycleExecutionException
-    {
-        Set<Artifact> artifacts;
+            ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
 
-        try
-        {
-            try
-            {
-                artifacts = projectDependenciesResolver.resolve( project, scopesToCollect, scopesToResolve, session );
-            }
-            catch ( MultipleArtifactsNotFoundException e )
-            {
-                /*
-                 * MNG-2277, the check below compensates for our bad plugin support where we ended up with aggregator
-                 * plugins that require dependency resolution although they usually run in phases of the build where project
-                 * artifacts haven't been assembled yet. The prime example of this is "mvn release:prepare".
-                 */
-                if ( aggregating && areAllArtifactsInReactor( session.getProjects(), e.getMissingArtifacts() ) )
-                {
-                    logger.warn( "The following artifacts could not be resolved at this point of the build"
-                        + " but seem to be part of the reactor:" );
+            BuildContext callableContext = new BuildContext(result, projectIndex, oldContextClassLoader);
 
-                    for ( Artifact artifact : e.getMissingArtifacts() )
-                    {
-                        logger.warn( "o " + artifact.getId() );
-                    }
+            Integer threadCount = getThreadCount(session.getRequest().getWeaveConfiguration());
 
-                    logger.warn( "Try running the build up to the lifecycle phase \"package\"" );
+            if (isWeave) {
 
-                    artifacts = new LinkedHashSet<Artifact>( e.getResolvedArtifacts() );
-                }
-                else
-                {
-                    throw e;
+                final int largestBuildListSize = projectBuilds.sizeOfLargestBuildList();
+                final boolean allowBendingLifeCycleOrder = executionRequest.getSystemProperties().
+                                                                 getProperty("maven.threads.violate.lifecycle") != null;
+                if (!allowBendingLifeCycleOrder){
+                    // No more threads than modules in largest build list is the constraint
+                    int option1 = (threadCount != null) ? threadCount : Runtime.getRuntime().availableProcessors();
+                    threadCount = Math.min( option1 , largestBuildListSize);
                 }
-            }
-        }
-        catch ( ArtifactResolutionException e )
-        {
-            throw new LifecycleExecutionException( null, project, e );
-        }
-        catch ( ArtifactNotFoundException e )
-        {
-            throw new LifecycleExecutionException( null, project, e );
-        }
+                boolean isLimitedThreads = threadCount != null;
 
-        project.setArtifacts( artifacts );
-
-        if ( project.getDependencyArtifacts() == null )
-        {
-            Set<String> directDependencies = new HashSet<String>( project.getDependencies().size() * 2 );
-            for ( Dependency dependency : project.getDependencies() )
-            {
-                directDependencies.add( dependency.getManagementKey() );
-            }
+                ExecutorService executor = isLimitedThreads ? Executors.newFixedThreadPool(threadCount) :
+                        Executors.newCachedThreadPool();
+                try {
+                    boolean canScheduleAggressively = allowBendingLifeCycleOrder &&
+                                                      (!isLimitedThreads || threadCount > largestBuildListSize) ;
+                    CompletionService<ProjectBuild> service = new ExecutorCompletionService<ProjectBuild>(executor);
+                    lifeCycleWeaveBuilder.buildProject(projectBuilds, callableContext, session, service, canScheduleAggressively);
+                } finally {
+                    executor.shutdown();
 
-            Set<Artifact> dependencyArtifacts = new LinkedHashSet<Artifact>( project.getDependencies().size() * 2 );
-            for ( Artifact artifact : artifacts )
-            {
-                if ( directDependencies.contains( artifact.getDependencyConflictId() ) )
-                {
-                    dependencyArtifacts.add( artifact );
                 }
+            } else {
+                singleThreadedBuild(session, callableContext, projectBuilds);
             }
-            project.setDependencyArtifacts( dependencyArtifacts );
         }
-    }
-
-    private boolean areAllArtifactsInReactor( Collection<MavenProject> projects, Collection<Artifact> artifacts )
-    {
-        Set<String> projectKeys = new HashSet<String>( projects.size() * 2 );
-        for ( MavenProject project : projects )
-        {
-            String key = ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() );
-            projectKeys.add( key );
-        }
-
-        for ( Artifact artifact : artifacts )
-        {
-            String key = ArtifactUtils.key( artifact );
-            if ( !projectKeys.contains( key ) )
-            {
-                return false;
-            }
+        catch (Exception e) {
+            result.addException(e);
         }
 
-        return true;
+        fireEvent(session, null, LifecycleEventCatapult.SESSION_ENDED);
     }
 
-    private class DependencyContext
-    {
-
-        private final Collection<String> scopesToCollect;
-
-        private final Collection<String> scopesToResolve;
-
-        private final boolean aggregating;
-
-        private MavenProject lastProject;
-
-        private Collection<?> lastDependencyArtifacts;
-
-        private int lastDependencyArtifactCount;
-
-        DependencyContext( Collection<String> scopesToCollect, Collection<String> scopesToResolve, boolean aggregating )
-        {
-            this.scopesToCollect = scopesToCollect;
-            this.scopesToResolve = scopesToResolve;
-            this.aggregating = aggregating;
-        }
-
-        DependencyContext( MavenExecutionPlan executionPlan, boolean aggregating )
-        {
-            this.scopesToCollect = executionPlan.getRequiredCollectionScopes();
-            this.scopesToResolve = executionPlan.getRequiredResolutionScopes();
-            this.aggregating = aggregating;
-        }
-
-        DependencyContext( MojoExecution mojoExecution )
-        {
-            this.scopesToCollect = new TreeSet<String>();
-            this.scopesToResolve = new TreeSet<String>();
-            collectDependencyRequirements( scopesToResolve, scopesToCollect, mojoExecution );
-            this.aggregating = mojoExecution.getMojoDescriptor().isAggregating();
-        }
-
-        public DependencyContext clone()
-        {
-            return new DependencyContext( scopesToCollect, scopesToResolve, aggregating );
-        }
-
-        void checkForUpdate( MavenSession session )
-            throws LifecycleExecutionException
-        {
-            if ( lastProject == session.getCurrentProject() )
-            {
-                if ( lastDependencyArtifacts != lastProject.getDependencyArtifacts()
-                    || ( lastDependencyArtifacts != null && lastDependencyArtifactCount != lastDependencyArtifacts.size() ) )
-                {
-                    logger.debug( "Re-resolving dependencies for project " + lastProject.getId()
-                        + " to account for updates by previous goal execution" );
-                    resolveProjectDependencies( lastProject, scopesToCollect, scopesToResolve, session, aggregating );
+    private void singleThreadedBuild(MavenSession session, BuildContext callableContext, ProjectBuildList projectBuilds) {
+        int chunkNo = 0;
+        for (ProjectBuildList segmentChunks : projectBuilds.getByTaskSegments()) {
+            for (ProjectBuild projectBuild : segmentChunks) {
+                try {
+                    // Aw man if this works.
+                    List<TaskSegment> currentTaskSegment = buildListCalculator.calculateTaskSegments(session);
+                    lifeCycleBuilder.buildProject(session, callableContext, projectBuild.getProject(), currentTaskSegment.get(chunkNo));
+                    if (session.isHalted()) break;
                 }
-            }
-
-            lastProject = session.getCurrentProject();
-            lastDependencyArtifacts = lastProject.getDependencyArtifacts();
-            lastDependencyArtifactCount = ( lastDependencyArtifacts != null ) ? lastDependencyArtifacts.size() : 0;
-        }
-    }
-
-    private void execute( MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex,
-                          DependencyContext dependencyContext )
-        throws LifecycleExecutionException
-    {
-        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
-
-        if ( mojoDescriptor.isProjectRequired() && !session.isUsingPOMsFromFilesystem() )
-        {
-            Throwable cause =
-                new IllegalStateException( "Goal requires a project to execute but there is no POM in this build." );
-            throw new LifecycleExecutionException( mojoExecution, null, cause );
-        }
-
-        if ( mojoDescriptor.isOnlineRequired() && session.isOffline() )
-        {
-            if ( MojoExecution.Source.CLI.equals( mojoExecution.getSource() ) )
-            {
-                Throwable cause =
-                    new IllegalStateException( "Goal requires online mode for execution"
-                        + " but Maven is currently offline." );
-                throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), cause );
-            }
-            else
-            {
-                fireEvent( session, mojoExecution, LifecycleEventCatapult.MOJO_SKIPPED );
-
-                return;
-            }
-        }
-
-        dependencyContext.checkForUpdate( session );
-
-        List<MavenProject> forkedProjects =
-            executeForkedExecutions( mojoExecution, session, projectIndex, dependencyContext );
-
-        fireEvent( session, mojoExecution, LifecycleEventCatapult.MOJO_STARTED );
-
-        try
-        {
-            try
-            {
-                pluginManager.executeMojo( session, mojoExecution );
-            }
-            catch ( MojoFailureException e )
-            {
-                throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e );
-            }
-            catch ( MojoExecutionException e )
-            {
-                throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e );
-            }
-            catch ( PluginConfigurationException e )
-            {
-                throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e );
-            }
-            catch ( PluginManagerException e )
-            {
-                throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e );
-            }
-
-            fireEvent( session, mojoExecution, LifecycleEventCatapult.MOJO_SUCCEEDED );
-        }
-        catch ( LifecycleExecutionException e )
-        {
-            fireEvent( session, mojoExecution, LifecycleEventCatapult.MOJO_FAILED );
-
-            throw e;
-        }
-        finally
-        {
-            for ( MavenProject forkedProject : forkedProjects )
-            {
-                forkedProject.setExecutionProject( null );
-            }
-        }
-    }
-
-    public List<MavenProject> executeForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-        throws LifecycleExecutionException
-    {
-        return executeForkedExecutions( mojoExecution, session, new ProjectIndex( session.getProjects() ),
-                                        new DependencyContext( mojoExecution ) );
-    }
-
-    private List<MavenProject> executeForkedExecutions( MojoExecution mojoExecution, MavenSession session,
-                                                        ProjectIndex projectIndex, DependencyContext dependencyContext )
-        throws LifecycleExecutionException
-    {
-        List<MavenProject> forkedProjects = Collections.emptyList();
-
-        Map<String, List<MojoExecution>> forkedExecutions = mojoExecution.getForkedExecutions();
-
-        if ( !forkedExecutions.isEmpty() )
-        {
-            fireEvent( session, mojoExecution, LifecycleEventCatapult.FORK_STARTED );
-
-            MavenProject project = session.getCurrentProject();
-
-            forkedProjects = new ArrayList<MavenProject>( forkedExecutions.size() );
-
-            dependencyContext = dependencyContext.clone();
-
-            try
-            {
-                for ( Map.Entry<String, List<MojoExecution>> fork : forkedExecutions.entrySet() )
-                {
-                    int index = projectIndex.indices.get( fork.getKey() );
-
-                    MavenProject forkedProject = projectIndex.projects.get( fork.getKey() );
-
-                    forkedProjects.add( forkedProject );
-
-                    MavenProject executedProject = forkedProject.clone();
-
-                    forkedProject.setExecutionProject( executedProject );
-
-                    try
-                    {
-                        session.setCurrentProject( executedProject );
-                        session.getProjects().set( index, executedProject );
-                        projectIndex.projects.put( fork.getKey(), executedProject );
-
-                        for ( MojoExecution forkedExecution : fork.getValue() )
-                        {
-                            execute( session, forkedExecution, projectIndex, dependencyContext );
-                        }
-                    }
-                    finally
-                    {
-                        projectIndex.projects.put( fork.getKey(), forkedProject );
-                        session.getProjects().set( index, forkedProject );
-                        session.setCurrentProject( project );
-                    }
-                }
-
-                fireEvent( session, mojoExecution, LifecycleEventCatapult.FORK_SUCCEEDED );
-            }
-            catch ( LifecycleExecutionException e )
-            {
-                fireEvent( session, mojoExecution, LifecycleEventCatapult.FORK_FAILED );
-
-                throw e;
-            }
-        }
-
-        return forkedProjects;
-    }
-
-    private static final class ProjectIndex
-    {
-
-        Map<String, MavenProject> projects;
-
-        Map<String, Integer> indices;
-
-        ProjectIndex( List<MavenProject> projects )
-        {
-            this.projects = new HashMap<String, MavenProject>( projects.size() * 2 );
-            this.indices = new HashMap<String, Integer>( projects.size() * 2 );
-
-            for ( int i = 0; i < projects.size(); i++ )
-            {
-                MavenProject project = projects.get( i );
-                String key = getKey( project );
-
-                this.projects.put( key, project );
-                this.indices.put( key, Integer.valueOf( i ) );
-            }
-        }
-
-    }
-
-    private List<ProjectBuild> calculateProjectBuilds( MavenSession session )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginVersionResolutionException
-    {
-        List<ProjectBuild> projectBuilds = new ArrayList<ProjectBuild>();
-
-        MavenProject rootProject = session.getTopLevelProject();
-
-        List<String> tasks = session.getGoals();
-
-        if ( tasks == null || tasks.isEmpty() )
-        {
-            if ( !StringUtils.isEmpty( rootProject.getDefaultGoal() ) )
-            {
-                tasks = Collections.singletonList( rootProject.getDefaultGoal() );
-            }
-        }
-
-        List<TaskSegment> taskSegments = calculateTaskSegments( session, tasks );
-
-        for ( TaskSegment taskSegment : taskSegments )
-        {
-            List<MavenProject> projects;
-
-            if ( taskSegment.aggregating )
-            {
-                projects = Collections.singletonList( rootProject );
-            }
-            else
-            {
-                projects = session.getProjects();
-            }
-
-            for ( MavenProject project : projects )
-            {
-                projectBuilds.add( new ProjectBuild( project, taskSegment ) );
-            }
-        }
-
-        return projectBuilds;
-    }
-
-    private MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project,
-                                                       TaskSegment taskSegment )
-        throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
-        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
-        NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-        resolveMissingPluginVersions( project, session );
-
-        List<MojoExecution> mojoExecutions = new ArrayList<MojoExecution>();
-
-        Set<String> requiredDependencyResolutionScopes = new TreeSet<String>();
-
-        Set<String> requiredDependencyCollectionScopes = new TreeSet<String>();
-
-        for ( Object task : taskSegment.tasks )
-        {
-            if ( task instanceof GoalTask )
-            {
-                MojoDescriptor mojoDescriptor = ( (GoalTask) task ).mojoDescriptor;
-
-                MojoExecution mojoExecution =
-                    new MojoExecution( mojoDescriptor, "default-cli", MojoExecution.Source.CLI );
-
-                mojoExecutions.add( mojoExecution );
-            }
-            else if ( task instanceof LifecycleTask )
-            {
-                String lifecyclePhase = ( (LifecycleTask) task ).lifecyclePhase;
-
-                Map<String, List<MojoExecution>> phaseToMojoMapping =
-                    calculateLifecycleMappings( session, project, lifecyclePhase );
-
-                for ( List<MojoExecution> mojoExecutionsFromLifecycle : phaseToMojoMapping.values() )
-                {
-                    mojoExecutions.addAll( mojoExecutionsFromLifecycle );
+                catch (Exception e) {
+                    break;  // Why are we just ignoring this exception? I think exceptions are being used for flow control
                 }
             }
-            else
-            {
-                throw new IllegalStateException( "unexpected task " + task );
-            }
-        }
-
-        for ( MojoExecution mojoExecution : mojoExecutions )
-        {
-            MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
-
-            if ( mojoDescriptor == null )
-            {
-                mojoDescriptor =
-                    pluginManager.getMojoDescriptor( mojoExecution.getPlugin(), mojoExecution.getGoal(),
-                                                     getRepositoryRequest( session, project ) );
-
-                mojoExecution.setMojoDescriptor( mojoDescriptor );
-            }
-
-            populateMojoExecutionConfiguration( project, mojoExecution,
-                                                MojoExecution.Source.CLI.equals( mojoExecution.getSource() ) );
-
-            finalizeMojoConfiguration( mojoExecution );
-
-            calculateForkedExecutions( mojoExecution, session, project, new HashSet<MojoDescriptor>() );
-
-            collectDependencyRequirements( requiredDependencyResolutionScopes, requiredDependencyCollectionScopes,
-                                           mojoExecution );
+            chunkNo++;
         }
-
-        return new MavenExecutionPlan( mojoExecutions, requiredDependencyResolutionScopes,
-                                       requiredDependencyCollectionScopes );
     }
 
-    private List<TaskSegment> calculateTaskSegments( MavenSession session, List<String> tasks )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginVersionResolutionException
-    {
-        List<TaskSegment> taskSegments = new ArrayList<TaskSegment>( tasks.size() );
-
-        TaskSegment currentSegment = null;
-
-        for ( String task : tasks )
-        {
-            if ( isGoalSpecification( task ) )
-            {
-                // "pluginPrefix:goal" or "groupId:artifactId[:version]:goal"
-
-                MojoDescriptor mojoDescriptor = getMojoDescriptor( task, session, session.getTopLevelProject() );
-
-                boolean aggregating = mojoDescriptor.isAggregating();
-
-                if ( currentSegment == null || currentSegment.aggregating != aggregating )
-                {
-                    currentSegment = new TaskSegment( aggregating );
-                    taskSegments.add( currentSegment );
-                }
 
-                currentSegment.tasks.add( new GoalTask( mojoDescriptor ) );
+    private Integer getThreadCount(String threadCountProperty) {
+        Integer threadCount = null;
+        if (threadCountProperty != null) {
+            try {
+                threadCount = Integer.parseInt(threadCountProperty);
             }
-            else
-            {
-                // lifecycle phase
-
-                if ( currentSegment == null || currentSegment.aggregating )
-                {
-                    currentSegment = new TaskSegment( false );
-                    taskSegments.add( currentSegment );
-                }
-
-                currentSegment.tasks.add( new LifecycleTask( task ) );
+            catch (NumberFormatException e) {
+                logger.warn("Couldn't parse thread count, will default to " + threadCount + ": " + threadCountProperty);
             }
         }
-
-        return taskSegments;
-    }
-
-    private boolean isGoalSpecification( String task )
-    {
-        return task.indexOf( ':' ) >= 0;
-    }
-
-    private static final class ProjectBuild
-    {
-
-        final MavenProject project;
-
-        final TaskSegment taskSegment;
-
-        ProjectBuild( MavenProject project, TaskSegment taskSegment )
-        {
-            this.project = project;
-            this.taskSegment = taskSegment;
-        }
-
-        @Override
-        public String toString()
-        {
-            return project.getId() + " -> " + taskSegment;
+        if (logger.isDebugEnabled() && threadCount != null) {
+            logger.debug("Thread pool: " + threadCount);
         }
-
+        return threadCount;
     }
 
-    private static final class TaskSegment
-    {
-
-        final List<Object> tasks;
-
-        final boolean aggregating;
-
-        TaskSegment( boolean aggregating )
-        {
-            this.aggregating = aggregating;
-            tasks = new ArrayList<Object>();
-        }
-
-        @Override
-        public String toString()
-        {
-            return tasks.toString();
-        }
-
-    }
-
-    private static final class GoalTask
-    {
-
-        final MojoDescriptor mojoDescriptor;
-
-        GoalTask( MojoDescriptor mojoDescriptor )
-        {
-            this.mojoDescriptor = mojoDescriptor;
-        }
-
-        @Override
-        public String toString()
-        {
-            return mojoDescriptor.getId();
-        }
-
-    }
-
-    private static final class LifecycleTask
-    {
-
-        final String lifecyclePhase;
-
-        LifecycleTask( String lifecyclePhase )
-        {
-            this.lifecyclePhase = lifecyclePhase;
-        }
-
-        @Override
-        public String toString()
-        {
-            return lifecyclePhase;
-        }
-
-    }
-
-    public MavenExecutionPlan calculateExecutionPlan( MavenSession session, String... tasks )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginManagerException, LifecyclePhaseNotFoundException, LifecycleNotFoundException,
-        PluginVersionResolutionException
-    {
-        List<TaskSegment> taskSegments = calculateTaskSegments( session, Arrays.asList( tasks ) );
-
-        TaskSegment mergedSegment = new TaskSegment( false );
-
-        for ( TaskSegment taskSegment : taskSegments )
-        {
-            mergedSegment.tasks.addAll( taskSegment.tasks );
-        }
-
-        return calculateExecutionPlan( session, session.getCurrentProject(), mergedSegment );
-    }
-
-    private RepositoryRequest getRepositoryRequest( MavenSession session, MavenProject project )
-    {
-        RepositoryRequest request = new DefaultRepositoryRequest();
-
-        request.setCache( session.getRepositoryCache() );
-        request.setLocalRepository( session.getLocalRepository() );
-        if ( project != null )
-        {
-            request.setRemoteRepositories( project.getPluginArtifactRepositories() );
-        }
-        request.setOffline( session.isOffline() );
-        request.setForceUpdate( session.getRequest().isUpdateSnapshots() );
-        request.setTransferListener( session.getRequest().getTransferListener() );
-
-        return request;
-    }
-
-    private void collectDependencyRequirements( Collection<String> requiredDependencyResolutionScopes,
-                                                    Collection<String> requiredDependencyCollectionScopes,
-                                                    MojoExecution mojoExecution )
-    {
-        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
-
-        String requiredDependencyResolutionScope = mojoDescriptor.getDependencyResolutionRequired();
-
-        if ( StringUtils.isNotEmpty( requiredDependencyResolutionScope ) )
-        {
-            requiredDependencyResolutionScopes.add( requiredDependencyResolutionScope );
-        }
-
-        String requiredDependencyCollectionScope = mojoDescriptor.getDependencyCollectionRequired();
-
-        if ( StringUtils.isNotEmpty( requiredDependencyCollectionScope ) )
-        {
-            requiredDependencyCollectionScopes.add( requiredDependencyCollectionScope );
-        }
-
-        for ( List<MojoExecution> forkedExecutions : mojoExecution.getForkedExecutions().values() )
-        {
-            for ( MojoExecution forkedExecution : forkedExecutions )
-            {
-                collectDependencyRequirements( requiredDependencyResolutionScopes,
-                                                   requiredDependencyCollectionScopes, forkedExecution );
-            }
-        }
-    }
-
-    private Map<String, List<MojoExecution>> calculateLifecycleMappings( MavenSession session, MavenProject project,
-                                                                         String lifecyclePhase )
-        throws LifecyclePhaseNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException
-    {
-        /*
-         * Determine the lifecycle that corresponds to the given phase.
-         */
-
-        Lifecycle lifecycle = phaseToLifecycleMap.get( lifecyclePhase );
-
-        if ( lifecycle == null )
-        {
-            throw new LifecyclePhaseNotFoundException( lifecyclePhase );
-        }
-
-        /*
-         * Initialize mapping from lifecycle phase to bound mojos. The key set of this map denotes the phases the caller
-         * is interested in, i.e. all phases up to and including the specified phase.
-         */
-
-        Map<String, Map<Integer, List<MojoExecution>>> mappings =
-            new LinkedHashMap<String, Map<Integer, List<MojoExecution>>>();
-
-        for ( String phase : lifecycle.getPhases() )
-        {
-            Map<Integer, List<MojoExecution>> phaseBindings = new TreeMap<Integer, List<MojoExecution>>();
-
-            mappings.put( phase, phaseBindings );
-
-            if ( phase.equals( lifecyclePhase ) )
-            {
-                break;
-            }
-        }
-
-        /*
-         * Grab plugin executions that are bound to the selected lifecycle phases from project. The effective model of
-         * the project already contains the plugin executions induced by the project's packaging type. Remember, all
-         * phases of interest and only those are in the lifecyle mapping, if a phase has no value in the map, we are not
-         * interested in any of the executions bound to it.
-         */
-
-        for ( Plugin plugin : project.getBuild().getPlugins() )
-        {
-            for ( PluginExecution execution : plugin.getExecutions() )
-            {
-                // if the phase is specified then I don't have to go fetch the plugin yet and pull it down
-                // to examine the phase it is associated to.
-                if ( execution.getPhase() != null )
-                {
-                    Map<Integer, List<MojoExecution>> phaseBindings = mappings.get( execution.getPhase() );
-                    if ( phaseBindings != null )
-                    {
-                        for ( String goal : execution.getGoals() )
-                        {
-                            MojoExecution mojoExecution = new MojoExecution( plugin, goal, execution.getId() );
-                            addMojoExecution( phaseBindings, mojoExecution, execution.getPriority() );
-                        }
-                    }
-                }
-                // if not then i need to grab the mojo descriptor and look at the phase that is specified
-                else
-                {
-                    for ( String goal : execution.getGoals() )
-                    {
-                        MojoDescriptor mojoDescriptor =
-                            pluginManager.getMojoDescriptor( plugin, goal, getRepositoryRequest( session, project ) );
-
-                        Map<Integer, List<MojoExecution>> phaseBindings = mappings.get( mojoDescriptor.getPhase() );
-                        if ( phaseBindings != null )
-                        {
-                            MojoExecution mojoExecution = new MojoExecution( mojoDescriptor, execution.getId() );
-                            addMojoExecution( phaseBindings, mojoExecution, execution.getPriority() );
-                        }
-                    }
-                }
-            }
-        }
-
-        Map<String, List<MojoExecution>> lifecycleMappings = new LinkedHashMap<String, List<MojoExecution>>();
-
-        for ( Map.Entry<String, Map<Integer, List<MojoExecution>>> entry : mappings.entrySet() )
-        {
-            List<MojoExecution> mojoExecutions = new ArrayList<MojoExecution>();
-
-            for ( List<MojoExecution> executions : entry.getValue().values() )
-            {
-                mojoExecutions.addAll( executions );
-            }
-
-            lifecycleMappings.put( entry.getKey(), mojoExecutions );
-        }
-
-        return lifecycleMappings;
-    }
-
-    private void addMojoExecution( Map<Integer, List<MojoExecution>> phaseBindings, MojoExecution mojoExecution,
-                                   int priority )
-    {
-        List<MojoExecution> mojoExecutions = phaseBindings.get( priority );
-
-        if ( mojoExecutions == null )
-        {
-            mojoExecutions = new ArrayList<MojoExecution>();
-            phaseBindings.put( priority, mojoExecutions );
-        }
-
-        mojoExecutions.add( mojoExecution );
-    }
-
-    public void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-        calculateForkedExecutions( mojoExecution, session, session.getCurrentProject(), new HashSet<MojoDescriptor>() );
-    }
-
-    private void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session, MavenProject project,
-                                            Collection<MojoDescriptor> alreadyForkedExecutions )
-        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
-
-        if ( !mojoDescriptor.isForking() )
-        {
-            return;
-        }
-
-        if ( !alreadyForkedExecutions.add( mojoDescriptor ) )
-        {
-            return;
-        }
-
-        List<MavenProject> forkedProjects;
-
-        if ( mojoDescriptor.isAggregating() )
-        {
-            forkedProjects = session.getProjects();
-        }
-        else
-        {
-            forkedProjects = Collections.singletonList( project );
-        }
-
-        for ( MavenProject forkedProject : forkedProjects )
-        {
-            List<MojoExecution> forkedExecutions;
-
-            if ( StringUtils.isNotEmpty( mojoDescriptor.getExecutePhase() ) )
-            {
-                forkedExecutions =
-                    calculateForkedLifecycle( mojoExecution, session, forkedProject, alreadyForkedExecutions );
-            }
-            else
-            {
-                forkedExecutions = calculateForkedGoal( mojoExecution, session, forkedProject, alreadyForkedExecutions );
-            }
-
-            mojoExecution.setForkedExecutions( getKey( forkedProject ), forkedExecutions );
-        }
-
-        alreadyForkedExecutions.remove( mojoDescriptor );
-    }
-
-    private List<MojoExecution> calculateForkedGoal( MojoExecution mojoExecution, MavenSession session,
-                                                     MavenProject project,
-                                                     Collection<MojoDescriptor> alreadyForkedExecutions )
-        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
-
-        PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
-
-        String forkedGoal = mojoDescriptor.getExecuteGoal();
-
-        MojoDescriptor forkedMojoDescriptor = pluginDescriptor.getMojo( forkedGoal );
-        if ( forkedMojoDescriptor == null )
-        {
-            throw new MojoNotFoundException( forkedGoal, pluginDescriptor );
-        }
-
-        if ( alreadyForkedExecutions.contains( forkedMojoDescriptor ) )
-        {
-            return Collections.emptyList();
-        }
-
-        MojoExecution forkedExecution = new MojoExecution( forkedMojoDescriptor, forkedGoal );
-
-        populateMojoExecutionConfiguration( project, forkedExecution, true );
-
-        finalizeMojoConfiguration( forkedExecution );
-
-        calculateForkedExecutions( forkedExecution, session, project, alreadyForkedExecutions );
-
-        return Collections.singletonList( forkedExecution );
-    }
-
-    private List<MojoExecution> calculateForkedLifecycle( MojoExecution mojoExecution, MavenSession session,
-                                                          MavenProject project,
-                                                          Collection<MojoDescriptor> alreadyForkedExecutions )
-        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
-
-        String forkedPhase = mojoDescriptor.getExecutePhase();
-
-        Map<String, List<MojoExecution>> lifecycleMappings = calculateLifecycleMappings( session, project, forkedPhase );
-
-        for ( List<MojoExecution> forkedExecutions : lifecycleMappings.values() )
-        {
-            for ( MojoExecution forkedExecution : forkedExecutions )
-            {
-                if ( forkedExecution.getMojoDescriptor() == null )
-                {
-                    MojoDescriptor forkedMojoDescriptor =
-                        pluginManager.getMojoDescriptor( forkedExecution.getPlugin(), forkedExecution.getGoal(),
-                                                         getRepositoryRequest( session, project ) );
-
-                    forkedExecution.setMojoDescriptor( forkedMojoDescriptor );
-                }
-
-                populateMojoExecutionConfiguration( project, forkedExecution, false );
-            }
-        }
-
-        injectLifecycleOverlay( lifecycleMappings, mojoExecution, session, project );
-
-        List<MojoExecution> mojoExecutions = new ArrayList<MojoExecution>();
-
-        for ( List<MojoExecution> forkedExecutions : lifecycleMappings.values() )
-        {
-            for ( MojoExecution forkedExecution : forkedExecutions )
-            {
-                if ( !alreadyForkedExecutions.contains( forkedExecution.getMojoDescriptor() ) )
-                {
-                    finalizeMojoConfiguration( forkedExecution );
-
-                    calculateForkedExecutions( forkedExecution, session, project, alreadyForkedExecutions );
-
-                    mojoExecutions.add( forkedExecution );
-                }
-            }
-        }
-
-        return mojoExecutions;
-    }
-
-    private void injectLifecycleOverlay( Map<String, List<MojoExecution>> lifecycleMappings,
-                                         MojoExecution mojoExecution, MavenSession session, MavenProject project )
-        throws PluginDescriptorParsingException, LifecycleNotFoundException, MojoNotFoundException,
-        PluginNotFoundException, PluginResolutionException, NoPluginFoundForPrefixException,
-        InvalidPluginDescriptorException, PluginVersionResolutionException
-    {
-        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
-
-        PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
-
-        String forkedLifecycle = mojoDescriptor.getExecuteLifecycle();
-
-        if ( StringUtils.isEmpty( forkedLifecycle ) )
-        {
-            return;
-        }
-
-        org.apache.maven.plugin.lifecycle.Lifecycle lifecycleOverlay;
-
-        try
-        {
-            lifecycleOverlay = pluginDescriptor.getLifecycleMapping( forkedLifecycle );
-        }
-        catch ( IOException e )
-        {
-            throw new PluginDescriptorParsingException( pluginDescriptor.getPlugin(), pluginDescriptor.getSource(), e );
-        }
-        catch ( XmlPullParserException e )
-        {
-            throw new PluginDescriptorParsingException( pluginDescriptor.getPlugin(), pluginDescriptor.getSource(), e );
-        }
-
-        if ( lifecycleOverlay == null )
-        {
-            throw new LifecycleNotFoundException( forkedLifecycle );
-        }
-
-        for ( Phase phase : lifecycleOverlay.getPhases() )
-        {
-            List<MojoExecution> forkedExecutions = lifecycleMappings.get( phase.getId() );
-
-            if ( forkedExecutions != null )
-            {
-                for ( Execution execution : phase.getExecutions() )
-                {
-                    for ( String goal : execution.getGoals() )
-                    {
-                        MojoDescriptor forkedMojoDescriptor;
-
-                        if ( goal.indexOf( ':' ) < 0 )
-                        {
-                            forkedMojoDescriptor = pluginDescriptor.getMojo( goal );
-                            if ( forkedMojoDescriptor == null )
-                            {
-                                throw new MojoNotFoundException( goal, pluginDescriptor );
-                            }
-                        }
-                        else
-                        {
-                            forkedMojoDescriptor = getMojoDescriptor( goal, session, project );
-                        }
-
-                        MojoExecution forkedExecution =
-                            new MojoExecution( forkedMojoDescriptor, mojoExecution.getExecutionId() );
-
-                        Xpp3Dom forkedConfiguration = (Xpp3Dom) execution.getConfiguration();
-
-                        forkedExecution.setConfiguration( forkedConfiguration );
-
-                        populateMojoExecutionConfiguration( project, forkedExecution, true );
-
-                        forkedExecutions.add( forkedExecution );
-                    }
-                }
-
-                Xpp3Dom phaseConfiguration = (Xpp3Dom) phase.getConfiguration();
-
-                if ( phaseConfiguration != null )
-                {
-                    for ( MojoExecution forkedExecution : forkedExecutions )
-                    {
-                        Xpp3Dom forkedConfiguration = forkedExecution.getConfiguration();
-
-                        forkedConfiguration = Xpp3Dom.mergeXpp3Dom( phaseConfiguration, forkedConfiguration );
+    public static void fireEvent(MavenSession session, MojoExecution mojoExecution, LifecycleEventCatapult catapult) {
+        ExecutionListener listener = session.getRequest().getExecutionListener();
+        if (listener != null) {
+            ExecutionEvent event = new DefaultLifecycleEvent(session, mojoExecution);
 
-                        forkedExecution.setConfiguration( forkedConfiguration );
-                    }
-                }
-            }
+            catapult.fire(listener, event);
         }
     }
 
-    private void populateMojoExecutionConfiguration( MavenProject project, MojoExecution mojoExecution,
-                                                     boolean allowPluginLevelConfig )
-    {
-        String g = mojoExecution.getGroupId();
-
-        String a = mojoExecution.getArtifactId();
-
-        Plugin plugin = findPlugin( g, a, project.getBuildPlugins() );
-
-        if ( plugin == null && project.getPluginManagement() != null )
-        {
-            plugin = findPlugin( g, a, project.getPluginManagement().getPlugins() );
-        }
-
-        if ( plugin != null )
-        {
-            PluginExecution pluginExecution =
-                findPluginExecution( mojoExecution.getExecutionId(), plugin.getExecutions() );
-
-            Xpp3Dom pomConfiguration = null;
-
-            if ( pluginExecution != null )
-            {
-                pomConfiguration = (Xpp3Dom) pluginExecution.getConfiguration();
-            }
-            else if ( allowPluginLevelConfig )
-            {
-                pomConfiguration = (Xpp3Dom) plugin.getConfiguration();
-            }
-
-            Xpp3Dom mojoConfiguration = ( pomConfiguration != null ) ? new Xpp3Dom( pomConfiguration ) : null;
-
-            mojoConfiguration = Xpp3Dom.mergeXpp3Dom( mojoExecution.getConfiguration(), mojoConfiguration );
-
-            mojoExecution.setConfiguration( mojoConfiguration );
-        }
-    }
 
     /**
-     * Post-processes the effective configuration for the specified mojo execution. This step discards all parameters
-     * from the configuration that are not applicable to the mojo and injects the default values for any missing
-     * parameters.
-     * 
-     * @param mojoExecution The mojo execution whose configuration should be finalized, must not be {@code null}.
+     * * CRUFT GOES BELOW HERE ***
      */
-    private void finalizeMojoConfiguration( MojoExecution mojoExecution )
-    {
-        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
-
-        Xpp3Dom executionConfiguration = mojoExecution.getConfiguration();
-        if ( executionConfiguration == null )
-        {
-            executionConfiguration = new Xpp3Dom( "configuration" );
-        }
-
-        Xpp3Dom defaultConfiguration = getMojoConfiguration( mojoDescriptor );
-
-        Xpp3Dom finalConfiguration = new Xpp3Dom( "configuration" );
-
-        if ( mojoDescriptor.getParameters() != null )
-        {
-            for ( Parameter parameter : mojoDescriptor.getParameters() )
-            {
-                Xpp3Dom parameterConfiguration = executionConfiguration.getChild( parameter.getName() );
-
-                if ( parameterConfiguration == null )
-                {
-                    parameterConfiguration = executionConfiguration.getChild( parameter.getAlias() );
-                }
-
-                Xpp3Dom parameterDefaults = defaultConfiguration.getChild( parameter.getName() );
-
-                parameterConfiguration = Xpp3Dom.mergeXpp3Dom( parameterConfiguration, parameterDefaults, Boolean.TRUE );
-
-                if ( parameterConfiguration != null )
-                {
-                    parameterConfiguration = new Xpp3Dom( parameterConfiguration, parameter.getName() );
-
-                    if ( StringUtils.isEmpty( parameterConfiguration.getAttribute( "implementation" ) )
-                        && StringUtils.isNotEmpty( parameter.getImplementation() ) )
-                    {
-                        parameterConfiguration.setAttribute( "implementation", parameter.getImplementation() );
-                    }
-
-                    finalConfiguration.addChild( parameterConfiguration );
-                }
-            }
-        }
-
-        mojoExecution.setConfiguration( finalConfiguration );
-    }
-
-    // org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process
-    MojoDescriptor getMojoDescriptor( String task, MavenSession session, MavenProject project ) 
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException, PluginVersionResolutionException
-    {        
-        String goal = null;
-        
-        Plugin plugin = null;
-
-        StringTokenizer tok = new StringTokenizer( task, ":" );
-        
-        int numTokens = tok.countTokens();
-        
-        if ( numTokens == 4 )
-        {
-            // We have everything that we need
-            //
-            // org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process
-            //
-            // groupId
-            // artifactId
-            // version
-            // goal
-            //
-            plugin = new Plugin();
-            plugin.setGroupId( tok.nextToken() );
-            plugin.setArtifactId( tok.nextToken() );
-            plugin.setVersion( tok.nextToken() );
-            goal = tok.nextToken();
-            
-        }
-        else if ( numTokens == 3 )
-        {
-            // We have everything that we need except the version
-            //
-            // org.apache.maven.plugins:maven-remote-resources-plugin:???:process
-            //
-            // groupId
-            // artifactId
-            // ???
-            // goal
-            //
-            plugin = new Plugin();
-            plugin.setGroupId( tok.nextToken() );
-            plugin.setArtifactId( tok.nextToken() );
-            goal = tok.nextToken();
-        }
-        else if ( numTokens == 2 )
-        {
-            // We have a prefix and goal
-            //
-            // idea:idea
-            //
-            String prefix = tok.nextToken();
-            goal = tok.nextToken();
-
-            // This is the case where someone has executed a single goal from the command line
-            // of the form:
-            //
-            // mvn remote-resources:process
-            //
-            // From the metadata stored on the server which has been created as part of a standard
-            // Maven plugin deployment we will find the right PluginDescriptor from the remote
-            // repository.
-            
-            plugin = findPluginForPrefix( prefix, session );
-        }
-
-        injectPluginDeclarationFromProject( plugin, project );
-
-        RepositoryRequest repositoryRequest = getRepositoryRequest( session, project );
-
-        // If there is no version to be found then we need to look in the repository metadata for
-        // this plugin and see what's specified as the latest release.
-        //
-        if ( plugin.getVersion() == null )
-        {
-            resolvePluginVersion( plugin, repositoryRequest );
-        }
-
-        return pluginManager.getMojoDescriptor( plugin, goal, repositoryRequest );
-    }
-
-    private void resolvePluginVersion( Plugin plugin, RepositoryRequest repositoryRequest )
-        throws PluginVersionResolutionException
-    {
-        PluginVersionRequest versionRequest = new DefaultPluginVersionRequest( plugin, repositoryRequest );
-        plugin.setVersion( pluginVersionResolver.resolve( versionRequest ).getVersion() );
-    }
-
-    private void injectPluginDeclarationFromProject( Plugin plugin, MavenProject project )
-    {
-        Plugin pluginInPom = findPlugin( plugin, project.getBuildPlugins() );
-
-        if ( pluginInPom == null && project.getPluginManagement() != null )
-        {
-            pluginInPom = findPlugin( plugin, project.getPluginManagement().getPlugins() );
-        }
-
-        if ( pluginInPom != null )
-        {
-            if ( plugin.getVersion() == null )
-            {
-                plugin.setVersion( pluginInPom.getVersion() );
-            }
-
-            plugin.setDependencies( new ArrayList<Dependency>( pluginInPom.getDependencies() ) );
-        }
-    }
 
-    private Plugin findPlugin( Plugin plugin, Collection<Plugin> plugins )
-    {
-        return findPlugin( plugin.getGroupId(), plugin.getArtifactId(), plugins );
-    }
-
-    private Plugin findPlugin( String groupId, String artifactId, Collection<Plugin> plugins )
-    {
-        for ( Plugin plugin : plugins )
-        {
-            if ( artifactId.equals( plugin.getArtifactId() ) && groupId.equals( plugin.getGroupId() ) )
-            {
-                return plugin;
-            }
-        }
-
-        return null;
-    }
-
-    private PluginExecution findPluginExecution( String executionId, Collection<PluginExecution> executions )
-    {
-        if ( StringUtils.isNotEmpty( executionId ) )
-        {
-            for ( PluginExecution execution : executions )
-            {
-                if ( executionId.equals( execution.getId() ) )
-                {
-                    return execution;
-                }
-            }
-        }
-
-        return null;
-    }
-
-    public void initialize()
-        throws InitializationException
-    {
-        lifecycleMap = new HashMap<String,Lifecycle>();
-        
-        // If people are going to make their own lifecycles then we need to tell people how to namespace them correctly so
-        // that they don't interfere with internally defined lifecycles.
-
-        phaseToLifecycleMap = new HashMap<String,Lifecycle>();
-
-        for ( Lifecycle lifecycle : lifecycles )
-        {                        
-            for ( String phase : lifecycle.getPhases() )
-            {                
-                // The first definition wins.
-                if ( !phaseToLifecycleMap.containsKey( phase ) )
-                {
-                    phaseToLifecycleMap.put( phase, lifecycle );
-                }
-            }
-            
-            lifecycleMap.put( lifecycle.getId(), lifecycle );
-        }
-    }
-        
     // These methods deal with construction intact Plugin object that look like they come from a standard
     // <plugin/> block in a Maven POM. We have to do some wiggling to pull the sources of information
     // together and this really shows the problem of constructing a sensible default configuration but
     // it's all encapsulated here so it appears normalized to the POM builder.
-    
+
     // We are going to take the project packaging and find all plugin in the default lifecycle and create
     // fully populated Plugin objects, including executions with goals and default configuration taken
     // from the plugin.xml inside a plugin.
     //
-    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles( String packaging )
-    {
-        LifecycleMapping lifecycleMappingForPackaging = lifecycleMappings.get( packaging );
-
-        if ( lifecycleMappingForPackaging == null )
-        {
-            return null;
-        }
-
-        Map<Plugin, Plugin> plugins = new LinkedHashMap<Plugin, Plugin>();
-
-        for ( Lifecycle lifecycle : lifecycles )
-        {
-            org.apache.maven.lifecycle.mapping.Lifecycle lifecycleConfiguration =
-                lifecycleMappingForPackaging.getLifecycles().get( lifecycle.getId() );
-
-            Map<String, String> phaseToGoalMapping = null;
-
-            if ( lifecycleConfiguration != null )
-            {
-                phaseToGoalMapping = lifecycleConfiguration.getPhases();
-            }
-            else if ( lifecycle.getDefaultPhases() != null )
-            {
-                phaseToGoalMapping = lifecycle.getDefaultPhases();
-            }
-            
-            if ( phaseToGoalMapping != null )
-            {
-                // These are of the form:
-                //
-                // compile -> org.apache.maven.plugins:maven-compiler-plugin:compile[,gid:aid:goal,...]
-                //
-                for ( Map.Entry<String, String> goalsForLifecyclePhase : phaseToGoalMapping.entrySet() )
-                {
-                    String phase = goalsForLifecyclePhase.getKey();
-                    String goals = goalsForLifecyclePhase.getValue();
-                    if ( goals != null )
-                    {
-                        parseLifecyclePhaseDefinitions( plugins, phase, goals );
-                    }
-                }
-            }
-        }
-
-        return plugins.keySet();
-    }
-
-    private void parseLifecyclePhaseDefinitions( Map<Plugin, Plugin> plugins, String phase, String goals )
-    {
-        String[] mojos = StringUtils.split( goals, "," );
-
-        for ( int i = 0; i < mojos.length; i++ )
-        {
-            // either <groupId>:<artifactId>:<goal> or <groupId>:<artifactId>:<version>:<goal>
-            String goal = mojos[i].trim();
-            String[] p = StringUtils.split( goal, ":" );
-
-            PluginExecution execution = new PluginExecution();
-            execution.setId( "default-" + p[p.length - 1] );
-            execution.setPhase( phase );
-            execution.setPriority( i - mojos.length );
-            execution.getGoals().add( p[p.length - 1] );
-
-            Plugin plugin = new Plugin();
-            plugin.setGroupId( p[0] );
-            plugin.setArtifactId( p[1] );
-            if ( p.length >= 4 )
-            {
-                plugin.setVersion( p[2] );
-            }
-
-            Plugin existing = plugins.get( plugin );
-            if ( existing != null )
-            {
-                plugin = existing;
-            }
-            else
-            {
-                plugins.put( plugin, plugin );
-            }
-
-            plugin.getExecutions().add( execution );
-        }
-    }
-
-    private void resolveMissingPluginVersions( MavenProject project, MavenSession session )
-        throws PluginVersionResolutionException
-    {
-        for ( Plugin plugin : project.getBuildPlugins() )
-        {
-            if ( plugin.getVersion() == null )
-            {
-                PluginVersionRequest request = new DefaultPluginVersionRequest( plugin, session );
-                plugin.setVersion( pluginVersionResolver.resolve( request ).getVersion() );
-            }
-        }
-    }
-
-    public Xpp3Dom getMojoConfiguration( MojoDescriptor mojoDescriptor )
-    {
-        return convert( mojoDescriptor );
-    }
-        
-    Xpp3Dom convert( MojoDescriptor mojoDescriptor  )
-    {
-        Xpp3Dom dom = new Xpp3Dom( "configuration" );
-
-        PlexusConfiguration c = mojoDescriptor.getMojoConfiguration();
-
-        PlexusConfiguration[] ces = c.getChildren();
-
-        if ( ces != null )
-        {
-            for ( PlexusConfiguration ce : ces )
-            {
-                String value = ce.getValue( null );
-                String defaultValue = ce.getAttribute( "default-value", null );
-                if ( value != null || defaultValue != null )
-                {
-                    Xpp3Dom e = new Xpp3Dom( ce.getName() );
-                    e.setValue( value );
-                    if ( defaultValue != null )
-                    {
-                        e.setAttribute( "default-value", defaultValue );
-                    }
-                    dom.addChild( e );
-                }
-            }
-        }
-
-        return dom;
-    }
-
-    //TODO: take repo mans into account as one may be aggregating prefixes of many
-    //TODO: collect at the root of the repository, read the one at the root, and fetch remote if something is missing
-    //      or the user forces the issue
-    Plugin findPluginForPrefix( String prefix, MavenSession session )
-        throws NoPluginFoundForPrefixException
-    {        
-        // [prefix]:[goal]
-        
-        PluginPrefixRequest prefixRequest = new DefaultPluginPrefixRequest( prefix, session );
-        PluginPrefixResult prefixResult = pluginPrefixResolver.resolve( prefixRequest );
-        
-        Plugin plugin = new Plugin();
-        plugin.setGroupId( prefixResult.getGroupId() );
-        plugin.setArtifactId( prefixResult.getArtifactId() );
-
-        return plugin;
-    }
-
-    // These are checks that should be available in real time to IDEs
-
-    /*
-    checkRequiredMavenVersion( plugin, localRepository, project.getRemoteArtifactRepositories() );
-        // Validate against non-editable (@readonly) parameters, to make sure users aren't trying to override in the POM.
-        //validatePomConfiguration( mojoDescriptor, pomConfiguration );            
-        //checkDeprecatedParameters( mojoDescriptor, pomConfiguration );
-        //checkRequiredParameters( mojoDescriptor, pomConfiguration, expressionEvaluator );        
-    
-    public void checkRequiredMavenVersion( Plugin plugin, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories )
-        throws PluginVersionResolutionException, InvalidPluginException
-    {
-        // if we don't have the required Maven version, then ignore an update
-        if ( ( pluginProject.getPrerequisites() != null ) && ( pluginProject.getPrerequisites().getMaven() != null ) )
-        {
-            DefaultArtifactVersion requiredVersion = new DefaultArtifactVersion( pluginProject.getPrerequisites().getMaven() );
-
-            if ( runtimeInformation.getApplicationInformation().getVersion().compareTo( requiredVersion ) < 0 )
-            {
-                throw new PluginVersionResolutionException( plugin.getGroupId(), plugin.getArtifactId(), "Plugin requires Maven version " + requiredVersion );
-            }
-        }
-    }
-    
-   private void checkDeprecatedParameters( MojoDescriptor mojoDescriptor, PlexusConfiguration extractedMojoConfiguration )
-        throws PlexusConfigurationException
-    {
-        if ( ( extractedMojoConfiguration == null ) || ( extractedMojoConfiguration.getChildCount() < 1 ) )
-        {
-            return;
-        }
-
-        List<Parameter> parameters = mojoDescriptor.getParameters();
-
-        if ( ( parameters != null ) && !parameters.isEmpty() )
-        {
-            for ( Parameter param : parameters )
-            {
-                if ( param.getDeprecated() != null )
-                {
-                    boolean warnOfDeprecation = false;
-                    PlexusConfiguration child = extractedMojoConfiguration.getChild( param.getName() );
-
-                    if ( ( child != null ) && ( child.getValue() != null ) )
-                    {
-                        warnOfDeprecation = true;
-                    }
-                    else if ( param.getAlias() != null )
-                    {
-                        child = extractedMojoConfiguration.getChild( param.getAlias() );
-                        if ( ( child != null ) && ( child.getValue() != null ) )
-                        {
-                            warnOfDeprecation = true;
-                        }
-                    }
-
-                    if ( warnOfDeprecation )
-                    {
-                        StringBuilder buffer = new StringBuilder( 128 );
-                        buffer.append( "In mojo: " ).append( mojoDescriptor.getGoal() ).append( ", parameter: " ).append( param.getName() );
-
-                        if ( param.getAlias() != null )
-                        {
-                            buffer.append( " (alias: " ).append( param.getAlias() ).append( ")" );
-                        }
-
-                        buffer.append( " is deprecated:" ).append( "\n\n" ).append( param.getDeprecated() ).append( "\n" );
-
-                        logger.warn( buffer.toString() );
-                    }
-                }
-            }
-        }
+    // TODO: This whole method could probably removed by injecting lifeCyclePluginAnalyzer straight into client site.
+    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging) {
+        return lifeCyclePluginAnalyzer.getPluginsBoundByDefaultToAllLifecycles(packaging);
     }
-    
-   private void checkRequiredParameters( MojoDescriptor goal, PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator )
-        throws PluginConfigurationException
-    {
-        // TODO: this should be built in to the configurator, as we presently double process the expressions
-
-        List<Parameter> parameters = goal.getParameters();
-
-        if ( parameters == null )
-        {
-            return;
-        }
-
-        List<Parameter> invalidParameters = new ArrayList<Parameter>();
-
-        for ( int i = 0; i < parameters.size(); i++ )
-        {
-            Parameter parameter = parameters.get( i );
-
-            if ( parameter.isRequired() )
-            {
-                // the key for the configuration map we're building.
-                String key = parameter.getName();
-
-                Object fieldValue = null;
-                String expression = null;
-                PlexusConfiguration value = configuration.getChild( key, false );
-                try
-                {
-                    if ( value != null )
-                    {
-                        expression = value.getValue( null );
-
-                        fieldValue = expressionEvaluator.evaluate( expression );
-
-                        if ( fieldValue == null )
-                        {
-                            fieldValue = value.getAttribute( "default-value", null );
-                        }
-                    }
-
-                    if ( ( fieldValue == null ) && StringUtils.isNotEmpty( parameter.getAlias() ) )
-                    {
-                        value = configuration.getChild( parameter.getAlias(), false );
-                        if ( value != null )
-                        {
-                            expression = value.getValue( null );
-                            fieldValue = expressionEvaluator.evaluate( expression );
-                            if ( fieldValue == null )
-                            {
-                                fieldValue = value.getAttribute( "default-value", null );
-                            }
-                        }
-                    }
-                }
-                catch ( ExpressionEvaluationException e )
-                {
-                    throw new PluginConfigurationException( goal.getPluginDescriptor(), e.getMessage(), e );
-                }
-
-                // only mark as invalid if there are no child nodes
-                if ( ( fieldValue == null ) && ( ( value == null ) || ( value.getChildCount() == 0 ) ) )
-                {
-                    parameter.setExpression( expression );
-                    invalidParameters.add( parameter );
-                }
-            }
-        }
-
-        if ( !invalidParameters.isEmpty() )
-        {
-            throw new PluginParameterException( goal, invalidParameters );
-        }
-    }
-
-    private void validatePomConfiguration( MojoDescriptor goal, PlexusConfiguration pomConfiguration )
-        throws PluginConfigurationException
-    {
-        List<Parameter> parameters = goal.getParameters();
-
-        if ( parameters == null )
-        {
-            return;
-        }
-
-        for ( int i = 0; i < parameters.size(); i++ )
-        {
-            Parameter parameter = parameters.get( i );
-
-            // the key for the configuration map we're building.
-            String key = parameter.getName();
-
-            PlexusConfiguration value = pomConfiguration.getChild( key, false );
-
-            if ( ( value == null ) && StringUtils.isNotEmpty( parameter.getAlias() ) )
-            {
-                key = parameter.getAlias();
-                value = pomConfiguration.getChild( key, false );
-            }
-
-            if ( value != null )
-            {
-                // Make sure the parameter is either editable/configurable, or else is NOT specified in the POM
-                if ( !parameter.isEditable() )
-                {
-                    StringBuilder errorMessage = new StringBuilder( 128 ).append( "ERROR: Cannot override read-only parameter: " );
-                    errorMessage.append( key );
-                    errorMessage.append( " in goal: " ).append( goal.getFullGoalName() );
-
-                    throw new PluginConfigurationException( goal.getPluginDescriptor(), errorMessage.toString() );
-                }
-
-                String deprecated = parameter.getDeprecated();
-                if ( StringUtils.isNotEmpty( deprecated ) )
-                {
-                    logger.warn( "DEPRECATED [" + parameter.getName() + "]: " + deprecated );
-                }
-            }
-        }
-    }
-    
-    */    
 
     // USED BY MAVEN HELP PLUGIN
+
+    @SuppressWarnings({"UnusedDeclaration"})
     @Deprecated
-    public Map<String, Lifecycle> getPhaseToLifecycleMap()
-    {
-        return phaseToLifecycleMap;
+    public Map<String, Lifecycle> getPhaseToLifecycleMap() {
+        return defaultLifeCycles.getPhaseToLifecycleMap();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycles.java b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycles.java
new file mode 100644
index 0000000..dc124f8
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycles.java
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle;
+
+import org.apache.maven.lifecycle.internal.BuilderCommon;
+import org.apache.maven.lifecycle.internal.ExecutionPlanItem;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Jason van Zyl
+ * @author Kristian Rosenvold
+ */
+//TODO: The configuration for the lifecycle needs to be externalized so that I can use the annotations properly for the wiring and reference and external source for the lifecycle configuration.
+public class DefaultLifecycles implements Initializable {
+    // @Configuration(source="org/apache/maven/lifecycle/lifecycles.xml")
+    private List<Lifecycle> lifecycles;
+
+    private List<Scheduling> schedules;
+    /**
+     * We use this to display all the lifecycles available and their phases to users. Currently this is primarily
+     * used in the IDE integrations where a UI is presented to the user and they can select the lifecycle phase
+     * they would like to execute.
+     */
+    private Map<String,Lifecycle> lifecycleMap;
+
+    /**
+     * We use this to map all phases to the lifecycle that contains it. This is used so that a user can specify the
+     * phase they want to execute and we can easily determine what lifecycle we need to run.
+     */
+    private Map<String, Lifecycle> phaseToLifecycleMap;
+
+    public DefaultLifecycles() {
+    }
+
+    public DefaultLifecycles(List<Lifecycle> lifecycles, List<Scheduling> schedules) {
+        this.lifecycles = lifecycles;
+        this.schedules = schedules;
+    }
+
+    public void initialize()
+        throws InitializationException
+    {
+        lifecycleMap = new HashMap<String,Lifecycle>();
+
+        // If people are going to make their own lifecycles then we need to tell people how to namespace them correctly so
+        // that they don't interfere with internally defined lifecycles.
+
+        phaseToLifecycleMap = new HashMap<String,Lifecycle>();
+
+        for ( Lifecycle lifecycle : lifecycles )
+        {
+            for ( String phase : lifecycle.getPhases() )
+            {
+                // The first definition wins.
+                if ( !phaseToLifecycleMap.containsKey( phase ) )
+                {
+                    phaseToLifecycleMap.put( phase, lifecycle );
+                }
+            }
+
+            lifecycleMap.put( lifecycle.getId(), lifecycle );
+        }
+    }
+
+
+    public List<ExecutionPlanItem> createExecutionPlanItem(MavenProject mavenProject, List<MojoExecution> executions) throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException {
+        BuilderCommon.attachToThread(mavenProject);
+
+        List<ExecutionPlanItem> result = new ArrayList<ExecutionPlanItem>();
+        ExecutionPlanItem planNext = null;
+        for (MojoExecution mojoExecution : executions) {
+            String lifeCyclePhase = mojoExecution.getMojoDescriptor().getPhase();
+            final Scheduling scheduling = getScheduling("default");
+            Schedule schedule = null;
+            if (scheduling != null) {
+                schedule = scheduling.getSchedule(mojoExecution.getPlugin());
+                if (schedule == null)
+                    schedule = scheduling.getSchedule(lifeCyclePhase);
+            }
+            result.add( new ExecutionPlanItem(mojoExecution, schedule));
+
+        }
+        return result;
+    }
+
+
+    public  Scheduling getScheduling(String lifecyclePhaseName){
+        for (Scheduling schedule : schedules) {
+            if (lifecyclePhaseName.equals(schedule.getLifecycle()) )
+                return schedule;
+        }
+        return null;
+    }
+
+    public Lifecycle get(String key) {
+        return phaseToLifecycleMap.get(key);
+    }
+
+    public Map<String, Lifecycle> getPhaseToLifecycleMap() {
+        return phaseToLifecycleMap;
+    }
+
+    public List<Lifecycle> getLifeCycles() {
+        return lifecycles;
+    }
+
+    public List<Scheduling> getSchedules() {
+        return schedules;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifeCyclePluginAnalyzer.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifeCyclePluginAnalyzer.java
new file mode 100644
index 0000000..a498054
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifeCyclePluginAnalyzer.java
@@ -0,0 +1,28 @@
+
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle;
+
+import java.util.Set;
+import org.apache.maven.model.Plugin;
+
+
+/**
+ * @author Kristian Rosenvold
+ */
+public interface LifeCyclePluginAnalyzer {
+    Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging);
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/Lifecycle.java b/maven-core/src/main/java/org/apache/maven/lifecycle/Lifecycle.java
index 241dd12..2b01bdc 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/Lifecycle.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/Lifecycle.java
@@ -27,6 +27,14 @@ import java.util.Map;
  */
 public class Lifecycle
 {
+    public Lifecycle() {
+    }
+
+    public Lifecycle(String id, List<String> phases, Map<String, String> defaultPhases) {
+        this.id = id;
+        this.phases = phases;
+        this.defaultPhases = defaultPhases;
+    }
 
     // <lifecycle>
     //   <id>clean</id>
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleEventCatapult.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleEventCatapult.java
index 34b9f99..32094f1 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleEventCatapult.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleEventCatapult.java
@@ -28,7 +28,7 @@ import org.apache.maven.execution.ExecutionListener;
  * 
  * @author Benjamin Bentmann
  */
-interface LifecycleEventCatapult
+public interface LifecycleEventCatapult
 {
 
     /**
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
index f4504f3..c4a3f4c 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
@@ -1,4 +1,18 @@
 package org.apache.maven.lifecycle;
+/*
+ * 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.
+ */
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -52,19 +66,19 @@ public class LifecycleExecutionException
         this.project = project;
     }
 
-    LifecycleExecutionException( String message, MojoExecution execution, MavenProject project )
+    public LifecycleExecutionException( String message, MojoExecution execution, MavenProject project )
     {
         super( message );
         this.project = project;
     }
 
-    LifecycleExecutionException( String message, MojoExecution execution, MavenProject project, Throwable cause )
+    public LifecycleExecutionException( String message, MojoExecution execution, MavenProject project, Throwable cause )
     {
         super( message, cause );
         this.project = project;
     }
 
-    LifecycleExecutionException( MojoExecution execution, MavenProject project, Throwable cause )
+    public LifecycleExecutionException( MojoExecution execution, MavenProject project, Throwable cause )
     {
         this( createMessage( execution, project, cause ), execution, project, cause );
     }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutor.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutor.java
index e326865..6e5abc9 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutor.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutor.java
@@ -19,21 +19,10 @@ package org.apache.maven.lifecycle;
  * under the License.
  */
 
-import java.util.List;
 import java.util.Set;
 
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.model.Plugin;
-import org.apache.maven.plugin.InvalidPluginDescriptorException;
-import org.apache.maven.plugin.MojoExecution;
-import org.apache.maven.plugin.MojoNotFoundException;
-import org.apache.maven.plugin.PluginDescriptorParsingException;
-import org.apache.maven.plugin.PluginManagerException;
-import org.apache.maven.plugin.PluginNotFoundException;
-import org.apache.maven.plugin.PluginResolutionException;
-import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
-import org.apache.maven.plugin.version.PluginVersionResolutionException;
-import org.apache.maven.project.MavenProject;
 
 /**
  * @author Jason van  Zyl
@@ -45,25 +34,10 @@ public interface LifecycleExecutor
     @Deprecated
     String ROLE = LifecycleExecutor.class.getName();
 
-    /**
-     * Calculate the list of {@link org.apache.maven.plugin.descriptor.MojoDescriptor} objects to run for the selected lifecycle phase.
-     * 
-     * @param phase
-     * @param session
-     * @return
-     * @throws InvalidPluginDescriptorException 
-     * @throws LifecycleExecutionException
-     */
-    MavenExecutionPlan calculateExecutionPlan( MavenSession session, String... tasks )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException,
-        InvalidPluginDescriptorException, PluginManagerException, LifecyclePhaseNotFoundException,
-        LifecycleNotFoundException, PluginVersionResolutionException;
-        
     // For a given project packaging find all the plugins that are bound to any registered
     // lifecycles. The project builder needs to now what default plugin information needs to be
     // merged into POM being built. Once the POM builder has this plugin information, versions can be assigned
-    // by the POM builder because they will have to be defined in plugin management. Once this is done then it
+    // by the POM builder because they will have to be defined in plugin management. Once this is setComplete then it
     // can be passed back so that the default configuraiton information can be populated.
     //
     // We need to know the specific version so that we can lookup the right version of the plugin descriptor
@@ -77,33 +51,4 @@ public interface LifecycleExecutor
 
     void execute( MavenSession session );
 
-    /**
-     * Calculates the forked mojo executions requested by the mojo associated with the specified mojo execution.
-     * 
-     * @param mojoExecution The mojo execution for which to calculate the forked mojo executions, must not be {@code
-     *            null}.
-     * @param session The current build session that holds the projects and further settings, must not be {@code null}.
-     */
-    void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException;
-
-    /**
-     * Executes the previously calculated forked mojo executions of the given mojo execution. If the specified mojo
-     * execution requires no forking, this method does nothing. The return value denotes a subset of the projects from
-     * the session that have been forked. The method {@link MavenProject#getExecutionProject()} of those projects
-     * returns the project clone on which the forked execution were performed. It is the responsibility of the caller to
-     * reset those execution projects to {@code null} once they are no longer needed to free memory and to avoid
-     * accidental usage by unrelated mojos.
-     * 
-     * @param mojoExecution The mojo execution whose forked mojo executions should be processed, must not be {@code
-     *            null}.
-     * @param session The current build session that holds the projects and further settings, must not be {@code null}.
-     * @return The (unmodifiable) list of projects that have been forked, can be empty if no forking was required but
-     *         will never be {@code null}.
-     */
-    List<MavenProject> executeForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-        throws LifecycleExecutionException;
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/MavenExecutionPlan.java b/maven-core/src/main/java/org/apache/maven/lifecycle/MavenExecutionPlan.java
index 0f0972f..d48aa52 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/MavenExecutionPlan.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/MavenExecutionPlan.java
@@ -19,10 +19,9 @@ package org.apache.maven.lifecycle;
  * under the License.
  */
 
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 
-import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.lifecycle.internal.ExecutionPlanItem;
 
 //TODO: lifecycles being executed
 //TODO: what runs in each phase
@@ -30,30 +29,61 @@ import org.apache.maven.plugin.MojoExecution;
 //TODO: project dependencies that need downloading
 //TODO: unfortunately the plugins need to be downloaded in order to get the plugin.xml file. need to externalize this from the plugin archive.
 //TODO: this will be the class that people get in IDEs to modify
-public class MavenExecutionPlan
+public class MavenExecutionPlan  implements Iterable<ExecutionPlanItem>
 {
-    /** Individual executions that must be performed. */
-    private List<MojoExecution> executions;
-    
+
+    /*
+       At the moment, this class is totally immutable, and this is in line with thoughts about the
+       pre-calculated execution plan that stays the same during the execution.
+
+       If deciding to add mutable state to this class, it should be at least considered to
+       separate this into a separate mutable structure.
+
+     */
     /** For project dependency resolution, the scopes of resolution required if any. */
-    private Set<String> requiredDependencyResolutionScopes;
+    private final Set<String> requiredDependencyResolutionScopes;
 
     /** For project dependency collection, the scopes of collection required if any. */
-    private Set<String> requiredDependencyCollectionScopes;
+    private final Set<String> requiredDependencyCollectionScopes;
 
-    public MavenExecutionPlan( List<MojoExecution> executions, Set<String> requiredDependencyResolutionScopes,
-                               Set<String> requiredDependencyCollectionScopes )
-    {
-        this.executions = executions;
+    private final List<ExecutionPlanItem> planItem;
+
+    public MavenExecutionPlan(Set<String> requiredDependencyResolutionScopes, Set<String> requiredDependencyCollectionScopes, List<ExecutionPlanItem> planItem) {
         this.requiredDependencyResolutionScopes = requiredDependencyResolutionScopes;
         this.requiredDependencyCollectionScopes = requiredDependencyCollectionScopes;
+        this.planItem = planItem;
     }
 
-    public List<MojoExecution> getExecutions()
-    {
-        return executions;
+    public Iterator<ExecutionPlanItem> iterator() {
+        return getExecutionPlanItems().iterator();
+    }
+
+    /**
+     * Returns the first execution plan that has a schedule matching requested schedule
+     * @param desired The desired schedule
+     * @return The ExecutionPlanItem or null if none can be found
+     */
+    public ExecutionPlanItem findFirstWithMatchingSchedule(Schedule desired){
+        if (desired == null || desired.isMissingPhase()) return null;
+        for (ExecutionPlanItem executionPlanItem : getExecutionPlanItems()) {
+            if (executionPlanItem.hasSchedule( desired)) return executionPlanItem;
+        }
+        return null;
     }
 
+
+    private List<ExecutionPlanItem> getExecutionPlanItems()
+     {
+         return planItem;
+     }
+
+    public void forceAllComplete(){
+        for (ExecutionPlanItem executionPlanItem : getExecutionPlanItems()) {
+             executionPlanItem.forceComplete();
+        }
+    }
+
+
     public Set<String> getRequiredResolutionScopes()
     {
         return requiredDependencyResolutionScopes;
@@ -64,4 +94,7 @@ public class MavenExecutionPlan
         return requiredDependencyCollectionScopes;
     }
 
+    public int size() {
+        return planItem.size();
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/Schedule.java b/maven-core/src/main/java/org/apache/maven/lifecycle/Schedule.java
new file mode 100644
index 0000000..3f9821a
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/Schedule.java
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle;
+
+import org.apache.maven.model.Plugin;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class Schedule {
+    private String phase;
+    private String mojoClass;
+    private boolean mojoSynchronized;
+    // Indicates that the build cannot proceed until this phase (and all its upstreams) have been completed
+    private boolean outputDependant;
+    // Indicates that this phase can be skipped
+    private boolean forkable;
+
+    public Schedule() {
+    }
+
+    public Schedule(String phase, boolean mojoSynchronized, boolean outputDependant, boolean forkable) {
+        this.phase = phase;
+        this.mojoSynchronized = mojoSynchronized;
+        this.outputDependant = outputDependant;
+        this.forkable = forkable;
+    }
+
+
+    public boolean isMissingPhase(){
+        return null == phase;
+    }
+    public String getPhase() {
+        return phase;
+    }
+
+    public void setPhase(String phase) {
+        this.phase = phase;
+    }
+
+    public String getMojoClass() {
+        return mojoClass;
+    }
+
+    public void setMojoClass(String mojoClass) {
+        this.mojoClass = mojoClass;
+    }
+
+    public boolean isMojoSynchronized() {
+        return mojoSynchronized;
+    }
+
+    public void setMojoSynchronized(boolean mojoSynchronized) {
+        this.mojoSynchronized = mojoSynchronized;
+    }
+
+    public boolean isOutputDependant() {
+        return outputDependant;
+    }
+
+    public void setOutputDependant(boolean outputDependant) {
+        this.outputDependant = outputDependant;
+    }
+
+    public boolean isForkable() {
+        return forkable;
+    }
+
+    public void setForkable(boolean forkable) {
+        this.forkable = forkable;
+    }
+
+    @Override
+    public String toString() {
+        return "Schedule{" +
+                "phase='" + phase + '\'' +
+                ", mojoClass='" + mojoClass + '\'' +
+                ", mojoSynchronized=" + mojoSynchronized +
+                ", outputDependant=" + outputDependant +
+                ", forkable=" + forkable +
+                '}';
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/Scheduling.java b/maven-core/src/main/java/org/apache/maven/lifecycle/Scheduling.java
new file mode 100644
index 0000000..85ad571
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/Scheduling.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle;
+
+import org.apache.maven.model.Plugin;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class Scheduling.
+ */
+public class Scheduling
+{
+    private String lifecycle;
+
+    private List<Schedule> schedules;
+
+    public Scheduling() {
+    }
+
+    public Scheduling(String lifecycle, List<Schedule> schedules) {
+        this.lifecycle = lifecycle;
+        this.schedules = schedules;
+    }
+
+    public String getLifecycle() {
+        return lifecycle;
+    }
+
+    public void setLifecycle(String lifecycle) {
+        this.lifecycle = lifecycle;
+    }
+
+    public List<Schedule> getSchedules() {
+        return schedules;
+    }
+
+
+    public Schedule getSchedule(String phaseName){
+        if (phaseName == null) return null;
+        for (Schedule schedule : schedules) {
+            if (phaseName.equals(schedule.getPhase()) )
+                return schedule;
+        }
+        return null;
+    }
+    
+    public Schedule getSchedule(Plugin mojoClass){
+        if (mojoClass == null) return null;
+        for (Schedule schedule : schedules) {
+            if (mojoClass.getKey().equals(schedule.getMojoClass()) )
+                return schedule;
+        }
+        return null;
+    }
+
+    public void setSchedules(List<Schedule> schedules) {
+        this.schedules = schedules;
+    }
+}
\ No newline at end of file
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildContext.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildContext.java
new file mode 100644
index 0000000..91328fd
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildContext.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.execution.MavenSession;
+
+/**
+ * Context that is fixed for the entire build.
+ * @author Jason van Zyl
+ * @author Kristian Rosenvold
+ */
+
+public class BuildContext {
+    private final MavenExecutionResult result;
+    private final ProjectIndex projectIndex;
+    private final ClassLoader oldContextClassLoader;
+
+
+    public BuildContext(MavenExecutionResult result, ProjectIndex projectIndex, ClassLoader oldContextClassLoader) {
+        this.result = result;
+        this.projectIndex = projectIndex;
+        this.oldContextClassLoader = oldContextClassLoader;
+    }
+
+    public MavenExecutionResult getResult() {
+        return result;
+    }
+
+    public ProjectIndex getProjectIndex() {
+        return projectIndex;
+    }
+
+    public ClassLoader getOldContextClassLoader() {
+        return oldContextClassLoader;
+    }
+
+}
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
new file mode 100644
index 0000000..61c2141
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java
@@ -0,0 +1,89 @@
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.LifecycleNotFoundException;
+import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author Kristian Rosenvold
+ */
+@Component( role = BuildListCalculator.class)
+public class BuildListCalculator {
+    @Requirement
+    private LifecycleTaskSegmentCalculator lifeCycleTaskSegmentCalculator;
+
+    public BuildListCalculator() {
+    }
+
+    public BuildListCalculator(LifecycleTaskSegmentCalculator lifeCycleTaskSegmentCalculator) {
+        this.lifeCycleTaskSegmentCalculator = lifeCycleTaskSegmentCalculator;
+    }
+
+    public ProjectBuildList calculateProjectBuilds(MavenSession session)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+            MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+            PluginVersionResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
+
+        List<TaskSegment> taskSegments =calculateTaskSegments( session);
+       return calculateProjectBuilds( session, taskSegments);
+    }
+
+    public List<TaskSegment> calculateTaskSegments(MavenSession session)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+            MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+            PluginVersionResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
+
+        MavenProject rootProject = session.getTopLevelProject();
+
+        List<String> tasks = session.getGoals();
+
+        if (tasks == null || tasks.isEmpty()) {
+            if (!StringUtils.isEmpty(rootProject.getDefaultGoal())) {
+                tasks = Collections.singletonList(rootProject.getDefaultGoal());
+            }
+        }
+
+        return lifeCycleTaskSegmentCalculator.calculateTaskSegments(session, tasks);
+    }
+
+    private ProjectBuildList calculateProjectBuilds(MavenSession session, List<TaskSegment> taskSegments)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+            MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+            PluginVersionResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
+        List<ProjectBuild> projectBuilds = new ArrayList<ProjectBuild>();
+        List<ProjectBuild> lastInTaskSegment = new ArrayList<ProjectBuild>();
+
+        MavenProject rootProject = session.getTopLevelProject();
+
+         ProjectBuild projectBuild = null;
+        for (TaskSegment taskSegment : taskSegments) {
+            List<MavenProject> projects;
+            if (projectBuild != null) lastInTaskSegment.add(projectBuild);
+
+            if (taskSegment.isAggregating()) {
+                projects = Collections.singletonList(rootProject);
+            } else {
+                projects = session.getProjects();
+            }
+            for (MavenProject project : projects) {
+                BuilderCommon.attachToThread(project); // Not totally sure if this is needed for anything
+                MavenSession copiedSession = session.clone();
+                copiedSession.setCurrentProject(project);
+                projectBuild = new ProjectBuild(project, taskSegment, copiedSession);
+                projectBuilds.add(projectBuild);
+            }
+        }
+        return new ProjectBuildList(projectBuilds, lastInTaskSegment);
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuilderCommon.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuilderCommon.java
new file mode 100644
index 0000000..8e8c5d4
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuilderCommon.java
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.execution.BuildFailure;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.*;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Common code that is shared by the LifecycleModuleBuilder and the LifeCycleWeaveBuilder
+ *
+ * @author Kristian Rosenvold
+ *         Builds one or more lifecycles for a full module
+ */
+@Component(role = BuilderCommon.class)
+public class BuilderCommon {
+    @Requirement
+    private LifecycleDebugLogger lifecycleDebugLogger;
+    @Requirement
+    private LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator;
+    @Requirement
+    private LifecycleDependencyResolver lifecycleDependencyResolver;
+
+    @SuppressWarnings({"UnusedDeclaration"})
+    public BuilderCommon() {
+    }
+
+    public BuilderCommon(LifecycleDebugLogger lifecycleDebugLogger, LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator, LifecycleDependencyResolver lifecycleDependencyResolver) {
+        this.lifecycleDebugLogger = lifecycleDebugLogger;
+        this.lifeCycleExecutionPlanCalculator = lifeCycleExecutionPlanCalculator;
+        this.lifecycleDependencyResolver = lifecycleDependencyResolver;
+    }
+
+    public MavenExecutionPlan resolveBuildPlan(ProjectBuild projectBuild) throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException, LifecycleExecutionException {
+        return resolveBuildPlan( projectBuild.getSession(), projectBuild.getProject(), projectBuild.getTaskSegment());
+    }
+
+    public MavenExecutionPlan resolveBuildPlan(MavenSession session, MavenProject project, TaskSegment taskSegment) throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException, LifecycleExecutionException {
+        MavenExecutionPlan executionPlan = lifeCycleExecutionPlanCalculator.calculateExecutionPlan(session, project, taskSegment.getTasks());
+        lifecycleDebugLogger.debugProjectPlan(project, executionPlan);
+
+        // TODO: once we have calculated the build plan then we should accurately be able to download
+        // the project dependencies. Having it happen in the plugin manager is a tangled mess. We can optimize
+        // this later by looking at the build plan. Would be better to just batch download everything required
+        // by the reactor.
+
+        lifecycleDependencyResolver.resolveDependencies(taskSegment.isAggregating(), project, session, executionPlan);
+        return executionPlan;
+    }
+
+
+    public static void handleBuildError(
+            final MavenExecutionResult executionResult,
+            final MavenSession rootSession,
+            final MavenProject mavenProject,
+            final Exception e,
+            final long buildStartTime
+    ) {
+        executionResult.addException(e);
+
+        long buildEndTime = System.currentTimeMillis();
+
+        executionResult.addBuildSummary(new BuildFailure(mavenProject, buildEndTime - buildStartTime, e));
+
+        DefaultLifecycleExecutor.fireEvent(rootSession, null, LifecycleEventCatapult.PROJECT_FAILED);
+
+        if (MavenExecutionRequest.REACTOR_FAIL_NEVER.equals(rootSession.getReactorFailureBehavior())) {
+            // continue the build
+        } else if (MavenExecutionRequest.REACTOR_FAIL_AT_END.equals(rootSession.getReactorFailureBehavior())) {
+            // continue the build but ban all projects that depend on the failed one
+            rootSession.blackList(mavenProject);
+        } else if (MavenExecutionRequest.REACTOR_FAIL_FAST.equals(rootSession.getReactorFailureBehavior())) {
+            rootSession.halt();
+        } else {
+            throw new IllegalArgumentException("invalid reactor failure behavior "
+                    + rootSession.getReactorFailureBehavior());
+        }
+    }
+
+    public static void attachToThread(MavenProject currentProject) {
+        ClassRealm projectRealm = currentProject.getClassRealm();
+        if (projectRealm != null) {
+            Thread.currentThread().setContextClassLoader(projectRealm);
+        }
+    }
+
+    // Todo: I'm really wondering where this method belongs; smells like it should be on MavenProject, but for some reason it isn't ?
+    // This localization is kind-of a code smell.
+    public static String getKey(MavenProject project) {
+        return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion();
+    }
+
+
+}
\ No newline at end of file
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DependencyContext.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DependencyContext.java
new file mode 100644
index 0000000..988b819
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DependencyContext.java
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.project.MavenProject;
+
+import java.util.Collection;
+
+/**
+ * Context of dependency artifacts for the entire build.
+ *
+ * @author Benjamin Bentmann
+ * @author Kristian Rosenvold (class extract only)
+ */
+// TODO: From a concurrecy perspective, this class is not good. 
+public class DependencyContext
+{
+
+    private final Collection<String> scopesToCollect;
+
+    private final Collection<String> scopesToResolve;
+
+    private final boolean aggregating;
+
+    private volatile MavenProject lastProject;
+
+    private volatile Collection<?> lastDependencyArtifacts;
+
+    private volatile int lastDependencyArtifactCount;
+
+    private DependencyContext( Collection<String> scopesToCollect, Collection<String> scopesToResolve, boolean aggregating )
+    {
+        this.scopesToCollect = scopesToCollect;
+        this.scopesToResolve = scopesToResolve;
+        this.aggregating = aggregating;
+    }
+
+    public DependencyContext( MavenExecutionPlan executionPlan, boolean aggregating )
+    {
+        this(executionPlan.getRequiredCollectionScopes(), executionPlan.getRequiredResolutionScopes(), aggregating);
+    }
+
+    public void setLastDependencyArtifacts(Collection<?> lastDependencyArtifacts){
+        this.lastDependencyArtifacts = lastDependencyArtifacts;
+        lastDependencyArtifactCount = ( lastDependencyArtifacts != null ) ? lastDependencyArtifacts.size() : 0;
+    }
+
+    public MavenProject getLastProject() {
+        return lastProject;
+    }
+
+    public void setLastProject(MavenProject lastProject) {
+        this.lastProject = lastProject;
+    }
+
+    public Collection<String> getScopesToCollect() {
+        return scopesToCollect;
+    }
+
+    public Collection<String> getScopesToResolve() {
+        return scopesToResolve;
+    }
+
+    public boolean isAggregating() {
+        return aggregating;
+    }
+
+    public DependencyContext clone()
+    {
+        return new DependencyContext( scopesToCollect, scopesToResolve, aggregating );
+    }
+
+    public boolean isSameProject( MavenSession session )
+    {
+        return ( lastProject == session.getCurrentProject() );
+    }
+
+    public boolean isSameButUpdatedProject( MavenSession session ) {
+        if ( isSameProject(session))
+        {
+            if ( lastDependencyArtifacts != lastProject.getDependencyArtifacts()
+                || ( lastDependencyArtifacts != null && lastDependencyArtifactCount != lastDependencyArtifacts.size() ) )
+            {
+                return true;
+
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ExecutionPlanItem.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ExecutionPlanItem.java
new file mode 100644
index 0000000..faeaa73
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ExecutionPlanItem.java
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.lifecycle.Schedule;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Wraps individual MojoExecutions, containing information about completion status and scheduling.
+ * @author Kristian Rosenvold
+ */
+public class ExecutionPlanItem {
+    private final MojoExecution mojoExecution;
+    private final Schedule schedule;
+    // Completeness just indicates that it has been run or failed
+    private final AtomicBoolean complete = new AtomicBoolean(false);
+    private final Object monitor = new Object();
+
+    public ExecutionPlanItem(MojoExecution mojoExecution, Schedule schedule) {
+        this.mojoExecution = mojoExecution;
+        this.schedule = schedule;
+    }
+
+    public MojoExecution getMojoExecution() {
+        return mojoExecution;
+    }
+
+    public void setComplete(){
+        boolean transitionSuccessful = ensureComplete();
+        if (!transitionSuccessful) throw new IllegalStateException("Expected to be able to setComplete node, but was complete already");
+    }
+
+     public boolean ensureComplete(){
+        boolean f = complete.compareAndSet(false, true);
+        notifyListeners();
+        return f;
+    }
+
+    private void notifyListeners() {
+        synchronized ( monitor){
+            monitor.notifyAll();
+        }
+    }
+
+    public void forceComplete(){
+        final boolean b = complete.getAndSet(true);
+        if (!b) notifyListeners(); // Release anyone waiting for us
+    }
+
+    public void waitUntilDone() throws InterruptedException {
+        synchronized ( monitor){
+            while (!complete.get()){
+                monitor.wait();
+            }
+        }
+    }
+
+    public Schedule getSchedule() {
+        return schedule;
+    }
+
+    public boolean hasSchedule(Schedule other){
+        if (getSchedule() != null && !getSchedule().isMissingPhase()){
+            if ( other.getPhase().equals( getSchedule().getPhase()))
+                return true;
+        }
+        return false;
+    }
+
+    public Plugin getPlugin(){
+        final MojoDescriptor mojoDescriptor = getMojoExecution().getMojoDescriptor();
+        return mojoDescriptor.getPluginDescriptor().getPlugin();
+    }
+
+    @Override
+    public String toString() {
+        return "ExecutionPlanItem{" +
+                ", mojoExecution=" + mojoExecution +
+                ", schedule=" + schedule +
+                '}' + super.toString();
+    }
+
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/GoalTask.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/GoalTask.java
new file mode 100644
index 0000000..e82b919
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/GoalTask.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+
+/**
+ * A task that is a goal
+ *
+ * @author Benjamin Bentmann
+ */
+public final class GoalTask
+{
+
+    private final MojoDescriptor mojoDescriptor;
+
+    public GoalTask( MojoDescriptor mojoDescriptor )
+    {
+        this.mojoDescriptor = mojoDescriptor;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getMojoDescriptor().getId();
+    }
+
+    public MojoDescriptor getMojoDescriptor() {
+        return mojoDescriptor;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDebugLogger.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDebugLogger.java
new file mode 100644
index 0000000..cef835b
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDebugLogger.java
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.ProjectDependenciesResolver;
+import org.apache.maven.execution.BuildFailure;
+import org.apache.maven.execution.BuildSuccess;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.DefaultLifecycleExecutor;
+import org.apache.maven.lifecycle.LifecycleEventCatapult;
+import org.apache.maven.lifecycle.LifecycleExecutionException;
+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 org.codehaus.plexus.logging.Logger;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Logs debug output from the various lifecycle phases.
+ * @author Benjamin Bentmann
+ * @author Jason van Zyl
+ * @author Kristian Rosenvold (extracted class only)
+ */
+@Component( role = LifecycleDebugLogger.class)
+public class LifecycleDebugLogger {
+    @Requirement
+    private Logger logger;
+
+
+    @SuppressWarnings({"UnusedDeclaration"})
+    public LifecycleDebugLogger() {
+    }
+
+    public LifecycleDebugLogger(Logger logger) {
+        this.logger = logger;
+    }
+
+
+    public void debug(String s) {
+        logger.debug(s);
+    }
+
+    public void info(String s) {
+        logger.info(s);
+    }
+
+    public void debugReactorPlan(ProjectBuildList projectBuilds) {
+        if (!logger.isDebugEnabled()) return;
+        logger.debug("=== REACTOR BUILD PLAN ================================================");
+
+        for (Iterator<ProjectBuild> it = projectBuilds.iterator(); it.hasNext();) {
+            ProjectBuild projectBuild = it.next();
+
+            logger.debug("Project: " + projectBuild.getProject().getId());
+            logger.debug("Tasks:   " + projectBuild.getTaskSegment().getTasks());
+            logger.debug("Style:   " + (projectBuild.getTaskSegment().isAggregating() ? "Aggregating" : "Regular"));
+
+            if (it.hasNext()) {
+                logger.debug("-----------------------------------------------------------------------");
+            }
+        }
+
+        logger.debug("=======================================================================");
+    }
+
+
+    public void debugProjectPlan( MavenProject currentProject, MavenExecutionPlan executionPlan )
+    {
+        logger.debug( "=== PROJECT BUILD PLAN ================================================" );
+        logger.debug( "Project:       " + BuilderCommon.getKey( currentProject ) );
+        logger.debug( "Dependencies (collect): " + executionPlan.getRequiredCollectionScopes() );
+        logger.debug( "Dependencies (resolve): " + executionPlan.getRequiredResolutionScopes() );
+
+        for ( ExecutionPlanItem mojoExecution : executionPlan )
+        {
+            debugMojoExecution( mojoExecution.getMojoExecution() );
+        }
+
+        logger.debug( "=======================================================================" );
+    }
+
+    private void debugMojoExecution( MojoExecution mojoExecution )
+    {
+        String mojoExecId =
+            mojoExecution.getGroupId() + ':' + mojoExecution.getArtifactId() + ':' + mojoExecution.getVersion() + ':'
+                + mojoExecution.getGoal() + " (" + mojoExecution.getExecutionId() + ')';
+
+        Map<String, List<MojoExecution>> forkedExecutions = mojoExecution.getForkedExecutions();
+        if ( !forkedExecutions.isEmpty() )
+        {
+            for ( Map.Entry<String, List<MojoExecution>> fork : forkedExecutions.entrySet() )
+            {
+                logger.debug( "--- init fork of " + fork.getKey() + " for " + mojoExecId + " ---" );
+
+                for ( MojoExecution forkedExecution : fork.getValue() )
+                {
+                    debugMojoExecution( forkedExecution );
+                }
+
+                logger.debug( "--- exit fork of " + fork.getKey() + " for " + mojoExecId + " ---" );
+            }
+        }
+
+        logger.debug( "-----------------------------------------------------------------------" );
+        logger.debug( "Goal:          " + mojoExecId );
+        logger.debug( "Style:         "
+            + ( mojoExecution.getMojoDescriptor().isAggregating() ? "Aggregating" : "Regular" ) );
+        logger.debug( "Configuration: " + mojoExecution.getConfiguration() );
+    }
+
+}
\ No newline at end of file
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyAnalyzer.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyAnalyzer.java
new file mode 100644
index 0000000..356f596
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyAnalyzer.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.util.StringUtils;
+
+import java.util.Collection;
+import java.util.List;
+/**
+ * A task that is a goal
+ *
+ * @author Benjamin Bentmann
+ * @author Kristian Rosenvold (class extract)
+ */
+
+// TODO: Maybe move into LCEPCI
+public class LifecycleDependencyAnalyzer {
+    
+    public static void collectDependencyRequirements(Collection<String> requiredDependencyResolutionScopes,
+                                                     Collection<String> requiredDependencyCollectionScopes,
+                                                     MojoExecution mojoExecution) {
+        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
+
+        String requiredDependencyResolutionScope = mojoDescriptor.getDependencyResolutionRequired();
+
+        if (StringUtils.isNotEmpty(requiredDependencyResolutionScope)) {
+            requiredDependencyResolutionScopes.add(requiredDependencyResolutionScope);
+        }
+
+        String requiredDependencyCollectionScope = mojoDescriptor.getDependencyCollectionRequired();
+
+        if (StringUtils.isNotEmpty(requiredDependencyCollectionScope)) {
+            requiredDependencyCollectionScopes.add(requiredDependencyCollectionScope);
+        }
+
+        for (List<MojoExecution> forkedExecutions : mojoExecution.getForkedExecutions().values()) {
+            for (MojoExecution forkedExecution : forkedExecutions) {
+                collectDependencyRequirements(requiredDependencyResolutionScopes,
+                        requiredDependencyCollectionScopes, forkedExecution);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolver.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolver.java
new file mode 100644
index 0000000..a9d0352
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolver.java
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.ProjectDependenciesResolver;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.LifecycleExecutionException;
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.logging.Logger;
+
+import java.util.*;
+
+/**
+ * Resolves dependencies for the artifacts in context of the lifecycle build
+ *
+ * @author Benjamin Bentmann
+ * @author Jason van Zyl
+ * @author Kristian Rosenvold (extracted class)
+ */
+@Component( role = LifecycleDependencyResolver.class)
+public class LifecycleDependencyResolver {
+    @Requirement
+    private ProjectDependenciesResolver projectDependenciesResolver;
+    @Requirement
+    private Logger logger;
+
+    public LifecycleDependencyResolver() {
+    }
+
+    public LifecycleDependencyResolver(ProjectDependenciesResolver projectDependenciesResolver, Logger logger) {
+        this.projectDependenciesResolver = projectDependenciesResolver;
+        this.logger = logger;
+    }
+
+    public void resolveDependencies(boolean aggregating, MavenProject currentProject, MavenSession sessionForThisModule, MavenExecutionPlan executionPlan) throws LifecycleExecutionException {
+        List<MavenProject> projectsToResolve;
+        if (aggregating) {
+            projectsToResolve = sessionForThisModule.getProjects();
+        } else {
+            projectsToResolve = Collections.singletonList(currentProject);
+        }
+        resolveDependencies(aggregating, sessionForThisModule, executionPlan, projectsToResolve);
+    }
+
+  public void checkForUpdate( MavenSession session, DependencyContext dependenctContext)
+        throws LifecycleExecutionException
+    {
+
+        if (dependenctContext.isSameButUpdatedProject( session)){
+            resolveProjectDependencies( dependenctContext.getLastProject(), dependenctContext.getScopesToCollect(), dependenctContext.getScopesToResolve(), session, dependenctContext.isAggregating() );
+        }
+
+        dependenctContext.setLastProject( session.getCurrentProject());
+        dependenctContext.setLastDependencyArtifacts( session.getCurrentProject().getDependencyArtifacts());
+    }
+    
+    private void resolveDependencies(boolean aggregating, MavenSession session, MavenExecutionPlan executionPlan, List<MavenProject> projectsToResolve) throws LifecycleExecutionException {
+        for (MavenProject project : projectsToResolve) {
+            resolveProjectDependencies(project, executionPlan.getRequiredCollectionScopes(),
+                    executionPlan.getRequiredResolutionScopes(), session,
+                    aggregating);
+        }
+    }
+
+    private void resolveProjectDependencies(MavenProject project, Collection<String> scopesToCollect,
+                                           Collection<String> scopesToResolve, MavenSession session,
+                                           boolean aggregating)
+            throws LifecycleExecutionException {
+        Set<Artifact> artifacts = getProjectDependencies( project, scopesToCollect, scopesToResolve, session, aggregating);
+        updateProjectArtifacts(project, artifacts);
+    }
+
+    private void updateProjectArtifacts(MavenProject project, Set<Artifact> artifacts) {
+        project.setArtifacts(artifacts);
+
+        if (project.getDependencyArtifacts() == null) {
+            project.setDependencyArtifacts(getDependencyArtifacts(project, artifacts));
+        }
+    }
+
+    private Set<Artifact> getProjectDependencies(MavenProject project, Collection<String> scopesToCollect,
+                                           Collection<String> scopesToResolve, MavenSession session,
+                                           boolean aggregating)
+            throws LifecycleExecutionException {
+        Set<Artifact> artifacts;
+        try {
+        try {
+            artifacts = projectDependenciesResolver.resolve(project, scopesToCollect, scopesToResolve, session);
+        }
+        catch (MultipleArtifactsNotFoundException e) {
+            /*
+             * MNG-2277, the check below compensates for our bad plugin support where we ended up with aggregator
+             * plugins that require dependency resolution although they usually run in phases of the build where project
+             * artifacts haven't been assembled yet. The prime example of this is "mvn release:prepare".
+             */
+            if (aggregating && areAllArtifactsInReactor(session.getProjects(), e.getMissingArtifacts())) {
+                logger.warn("The following artifacts could not be resolved at this point of the build"
+                        + " but seem to be part of the reactor:");
+
+                for (Artifact artifact : e.getMissingArtifacts()) {
+                    logger.warn("o " + artifact.getId());
+                }
+
+                logger.warn("Try running the build up to the lifecycle phase \"package\"");
+
+                artifacts = new LinkedHashSet<Artifact>(e.getResolvedArtifacts());
+            } else {
+                throw e;
+            }
+        }
+
+        return artifacts;
+        } catch ( ArtifactResolutionException e )
+        {
+            throw new LifecycleExecutionException( null, project, e );
+        }
+        catch ( ArtifactNotFoundException e )
+        {
+            throw new LifecycleExecutionException( null, project, e );
+        }
+
+    }
+
+
+    private Set<Artifact> getDependencyArtifacts(MavenProject project, Set<Artifact> artifacts) {
+        Set<String> directDependencies = new HashSet<String>(project.getDependencies().size() * 2);
+        for (Dependency dependency : project.getDependencies()) {
+            directDependencies.add(dependency.getManagementKey());
+        }
+
+        Set<Artifact> dependencyArtifacts = new LinkedHashSet<Artifact>(project.getDependencies().size() * 2);
+        for (Artifact artifact : artifacts) {
+            if (directDependencies.contains(artifact.getDependencyConflictId())) {
+                dependencyArtifacts.add(artifact);
+            }
+        }
+        return dependencyArtifacts;
+    }
+
+    private boolean areAllArtifactsInReactor(Collection<MavenProject> projects, Collection<Artifact> artifacts) {
+        Set<String> projectKeys = new HashSet<String>(projects.size() * 2);
+        for (MavenProject project : projects) {
+            String key = ArtifactUtils.key(project.getGroupId(), project.getArtifactId(), project.getVersion());
+            projectKeys.add(key);
+        }
+
+        for (Artifact artifact : artifacts) {
+            String key = ArtifactUtils.key(artifact);
+            if (!projectKeys.contains(key)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculator.java
new file mode 100644
index 0000000..582db7b
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculator.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.LifecycleNotFoundException;
+import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+import org.apache.maven.project.MavenProject;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author Benjamin Bentmann
+ * @author Kristian Rosenvold  (extract interface only)
+ */
+public interface LifecycleExecutionPlanCalculator {
+    MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project,
+                                                       List<Object> tasks )
+        throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
+            PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
+            NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException;
+
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculatorImpl.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculatorImpl.java
new file mode 100644
index 0000000..fda3ff3
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculatorImpl.java
@@ -0,0 +1,549 @@
+/*
+ * 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.
+ */
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.artifact.repository.DefaultRepositoryRequest;
+import org.apache.maven.artifact.repository.RepositoryRequest;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.*;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginExecution;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.Parameter;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.plugin.lifecycle.Execution;
+import org.apache.maven.plugin.lifecycle.Phase;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
+import org.apache.maven.plugin.version.PluginVersionRequest;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+import org.apache.maven.plugin.version.PluginVersionResolver;
+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.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * @author Benjamin Bentmann
+ * @author Kristian Rosenvold (Extract class)
+ */
+@Component(role = LifecycleExecutionPlanCalculator.class)
+public class LifecycleExecutionPlanCalculatorImpl implements LifecycleExecutionPlanCalculator {
+    @Requirement
+    private PluginVersionResolver pluginVersionResolver;
+    @Requirement
+    private BuildPluginManager pluginManager;
+    @Requirement
+    private DefaultLifecycles defaultLifeCycles;
+    @Requirement
+    private MojoDescriptorCreator mojoDescriptorCreator;
+
+    public LifecycleExecutionPlanCalculatorImpl() {
+    }
+
+    public LifecycleExecutionPlanCalculatorImpl(PluginVersionResolver pluginVersionResolver, BuildPluginManager pluginManager, DefaultLifecycles defaultLifeCycles, MojoDescriptorCreator mojoDescriptorCreator) {
+        this.pluginVersionResolver = pluginVersionResolver;
+        this.pluginManager = pluginManager;
+        this.defaultLifeCycles = defaultLifeCycles;
+        this.mojoDescriptorCreator = mojoDescriptorCreator;
+    }
+
+    public MavenExecutionPlan calculateExecutionPlan(MavenSession session, MavenProject project,
+                                                     List<Object> tasks)
+            throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
+            PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
+            NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException {
+        Set<String> requiredDependencyResolutionScopes = new TreeSet<String>();
+        Set<String> requiredDependencyCollectionScopes = new TreeSet<String>();
+
+        final List<MojoExecution> executions = calculateExecutionPlan(session, project, tasks, requiredDependencyResolutionScopes, requiredDependencyCollectionScopes);
+        final List<ExecutionPlanItem> planItem = defaultLifeCycles.createExecutionPlanItem(project, executions);
+
+        return new MavenExecutionPlan(requiredDependencyResolutionScopes,
+                requiredDependencyCollectionScopes, planItem);
+
+
+    }
+
+    public List<MojoExecution> calculateExecutionPlan(MavenSession session, MavenProject project,
+                                                      List<Object> tasks, Set<String> requiredDependencyResolutionScopes, Set<String> requiredDependencyCollectionScopes)
+            throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
+            PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
+            NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException {
+        resolveMissingPluginVersions(project, session);
+
+        List<MojoExecution> mojoExecutions = new ArrayList<MojoExecution>();
+
+
+        for (Object task : tasks) {
+            if (task instanceof GoalTask) {
+                MojoDescriptor mojoDescriptor = ((GoalTask) task).getMojoDescriptor();
+
+                MojoExecution mojoExecution = new MojoExecution(mojoDescriptor, "default-cli", MojoExecution.Source.CLI);
+
+                mojoExecutions.add(mojoExecution);
+            } else if (task instanceof LifecycleTask) {
+                String lifecyclePhase = ((LifecycleTask) task).getLifecyclePhase();
+
+                Map<String, List<MojoExecution>> phaseToMojoMapping = calculateLifecycleMappings(session, project, lifecyclePhase);
+
+                for (List<MojoExecution> mojoExecutionsFromLifecycle : phaseToMojoMapping.values()) {
+                    mojoExecutions.addAll(mojoExecutionsFromLifecycle);
+                }
+            } else {
+                throw new IllegalStateException("unexpected task " + task);
+            }
+        }
+
+        for (MojoExecution mojoExecution : mojoExecutions) {
+            MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
+
+            if (mojoDescriptor == null) {
+                mojoDescriptor =
+                        pluginManager.getMojoDescriptor(mojoExecution.getPlugin(), mojoExecution.getGoal(),
+                                DefaultRepositoryRequest.getRepositoryRequest(session, project));
+
+                mojoExecution.setMojoDescriptor(mojoDescriptor);
+            }
+
+            populateMojoExecutionConfiguration(project, mojoExecution,
+                    MojoExecution.Source.CLI.equals(mojoExecution.getSource()));
+
+            finalizeMojoConfiguration(mojoExecution);
+
+            calculateForkedExecutions(mojoExecution, session, project, new HashSet<MojoDescriptor>());
+
+            LifecycleDependencyAnalyzer.collectDependencyRequirements(requiredDependencyResolutionScopes, requiredDependencyCollectionScopes,
+                    mojoExecution);
+        }
+
+        return mojoExecutions;
+    }
+
+
+    private Map<String, List<MojoExecution>> calculateLifecycleMappings(MavenSession session, MavenProject project,
+                                                                        String lifecyclePhase)
+            throws LifecyclePhaseNotFoundException, PluginNotFoundException, PluginResolutionException,
+            PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException {
+        /*
+         * Determine the lifecycle that corresponds to the given phase.
+         */
+
+        Lifecycle lifecycle = defaultLifeCycles.get(lifecyclePhase);
+
+        if (lifecycle == null) {
+            throw new LifecyclePhaseNotFoundException(lifecyclePhase);
+        }
+
+        /*
+         * Initialize mapping from lifecycle phase to bound mojos. The key set of this map denotes the phases the caller
+         * is interested in, i.e. all phases up to and including the specified phase.
+         */
+
+        Map<String, Map<Integer, List<MojoExecution>>> mappings =
+                new LinkedHashMap<String, Map<Integer, List<MojoExecution>>>();
+
+        for (String phase : lifecycle.getPhases()) {
+            Map<Integer, List<MojoExecution>> phaseBindings = new TreeMap<Integer, List<MojoExecution>>();
+
+            mappings.put(phase, phaseBindings);
+
+            if (phase.equals(lifecyclePhase)) {
+                break;
+            }
+        }
+
+        /*
+         * Grab plugin executions that are bound to the selected lifecycle phases from project. The effective model of
+         * the project already contains the plugin executions induced by the project's packaging type. Remember, all
+         * phases of interest and only those are in the lifecyle mapping, if a phase has no value in the map, we are not
+         * interested in any of the executions bound to it.
+         */
+
+        for (Plugin plugin : project.getBuild().getPlugins()) {
+            for (PluginExecution execution : plugin.getExecutions()) {
+                // if the phase is specified then I don't have to go fetch the plugin yet and pull it down
+                // to examine the phase it is associated to.
+                if (execution.getPhase() != null) {
+                    Map<Integer, List<MojoExecution>> phaseBindings = mappings.get(execution.getPhase());
+                    if (phaseBindings != null) {
+                        for (String goal : execution.getGoals()) {
+                            MojoExecution mojoExecution = new MojoExecution(plugin, goal, execution.getId());
+                            addMojoExecution(phaseBindings, mojoExecution, execution.getPriority());
+                        }
+                    }
+                }
+                // if not then i need to grab the mojo descriptor and look at the phase that is specified
+                else {
+                    for (String goal : execution.getGoals()) {
+                        MojoDescriptor mojoDescriptor =
+                                pluginManager.getMojoDescriptor(plugin, goal, DefaultRepositoryRequest.getRepositoryRequest(session, project));
+
+                        Map<Integer, List<MojoExecution>> phaseBindings = mappings.get(mojoDescriptor.getPhase());
+                        if (phaseBindings != null) {
+                            MojoExecution mojoExecution = new MojoExecution(mojoDescriptor, execution.getId());
+                            addMojoExecution(phaseBindings, mojoExecution, execution.getPriority());
+                        }
+                    }
+                }
+            }
+        }
+
+        Map<String, List<MojoExecution>> lifecycleMappings = new LinkedHashMap<String, List<MojoExecution>>();
+
+        for (Map.Entry<String, Map<Integer, List<MojoExecution>>> entry : mappings.entrySet()) {
+            List<MojoExecution> mojoExecutions = new ArrayList<MojoExecution>();
+
+            for (List<MojoExecution> executions : entry.getValue().values()) {
+                mojoExecutions.addAll(executions);
+            }
+
+            lifecycleMappings.put(entry.getKey(), mojoExecutions);
+        }
+
+        return lifecycleMappings;
+    }
+
+    private void addMojoExecution(Map<Integer, List<MojoExecution>> phaseBindings, MojoExecution mojoExecution,
+                                  int priority) {
+        List<MojoExecution> mojoExecutions = phaseBindings.get(priority);
+
+        if (mojoExecutions == null) {
+            mojoExecutions = new ArrayList<MojoExecution>();
+            phaseBindings.put(priority, mojoExecutions);
+        }
+
+        mojoExecutions.add(mojoExecution);
+    }
+
+    private void resolveMissingPluginVersions(MavenProject project, MavenSession session)
+            throws PluginVersionResolutionException {
+        for (Plugin plugin : project.getBuildPlugins()) {
+            if (plugin.getVersion() == null) {
+                PluginVersionRequest request = new DefaultPluginVersionRequest(plugin, session);
+                plugin.setVersion(pluginVersionResolver.resolve(request).getVersion());
+            }
+        }
+    }
+
+    private void populateMojoExecutionConfiguration(MavenProject project, MojoExecution mojoExecution,
+                                                    boolean allowPluginLevelConfig) {
+        String g = mojoExecution.getGroupId();
+
+        String a = mojoExecution.getArtifactId();
+
+        Plugin plugin = findPlugin(g, a, project.getBuildPlugins());
+
+        if (plugin == null && project.getPluginManagement() != null) {
+            plugin = findPlugin(g, a, project.getPluginManagement().getPlugins());
+        }
+
+        if (plugin != null) {
+            PluginExecution pluginExecution =
+                    findPluginExecution(mojoExecution.getExecutionId(), plugin.getExecutions());
+
+            Xpp3Dom pomConfiguration = null;
+
+            if (pluginExecution != null) {
+                pomConfiguration = (Xpp3Dom) pluginExecution.getConfiguration();
+            } else if (allowPluginLevelConfig) {
+                pomConfiguration = (Xpp3Dom) plugin.getConfiguration();
+            }
+
+            Xpp3Dom mojoConfiguration = (pomConfiguration != null) ? new Xpp3Dom(pomConfiguration) : null;
+
+            mojoConfiguration = Xpp3Dom.mergeXpp3Dom(mojoExecution.getConfiguration(), mojoConfiguration);
+
+            mojoExecution.setConfiguration(mojoConfiguration);
+        }
+    }
+
+    private Plugin findPlugin(String groupId, String artifactId, Collection<Plugin> plugins) {
+        for (Plugin plugin : plugins) {
+            if (artifactId.equals(plugin.getArtifactId()) && groupId.equals(plugin.getGroupId())) {
+                return plugin;
+            }
+        }
+
+        return null;
+    }
+
+    private PluginExecution findPluginExecution(String executionId, Collection<PluginExecution> executions) {
+        if (StringUtils.isNotEmpty(executionId)) {
+            for (PluginExecution execution : executions) {
+                if (executionId.equals(execution.getId())) {
+                    return execution;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Post-processes the effective configuration for the specified mojo execution. This step discards all parameters
+     * from the configuration that are not applicable to the mojo and injects the default values for any missing
+     * parameters.
+     *
+     * @param mojoExecution The mojo execution whose configuration should be finalized, must not be {@code null}.
+     */
+    private void finalizeMojoConfiguration(MojoExecution mojoExecution) {
+        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
+
+        Xpp3Dom executionConfiguration = mojoExecution.getConfiguration();
+        if (executionConfiguration == null) {
+            executionConfiguration = new Xpp3Dom("configuration");
+        }
+
+        Xpp3Dom defaultConfiguration = getMojoConfiguration(mojoDescriptor);
+
+        Xpp3Dom finalConfiguration = new Xpp3Dom("configuration");
+
+        if (mojoDescriptor.getParameters() != null) {
+            for (Parameter parameter : mojoDescriptor.getParameters()) {
+                Xpp3Dom parameterConfiguration = executionConfiguration.getChild(parameter.getName());
+
+                if (parameterConfiguration == null) {
+                    parameterConfiguration = executionConfiguration.getChild(parameter.getAlias());
+                }
+
+                Xpp3Dom parameterDefaults = defaultConfiguration.getChild(parameter.getName());
+
+                parameterConfiguration = Xpp3Dom.mergeXpp3Dom(parameterConfiguration, parameterDefaults, Boolean.TRUE);
+
+                if (parameterConfiguration != null) {
+                    parameterConfiguration = new Xpp3Dom(parameterConfiguration, parameter.getName());
+
+                    if (StringUtils.isEmpty(parameterConfiguration.getAttribute("implementation"))
+                            && StringUtils.isNotEmpty(parameter.getImplementation())) {
+                        parameterConfiguration.setAttribute("implementation", parameter.getImplementation());
+                    }
+
+                    finalConfiguration.addChild(parameterConfiguration);
+                }
+            }
+        }
+
+        mojoExecution.setConfiguration(finalConfiguration);
+    }
+
+    private Xpp3Dom getMojoConfiguration(MojoDescriptor mojoDescriptor) {
+        return MojoDescriptorCreator.convert(mojoDescriptor);
+    }
+
+    private void calculateForkedExecutions(MojoExecution mojoExecution, MavenSession session, MavenProject project,
+                                           Collection<MojoDescriptor> alreadyForkedExecutions)
+            throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
+            PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+            LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException {
+        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
+
+        if (!mojoDescriptor.isForking()) {
+            return;
+        }
+
+        if (!alreadyForkedExecutions.add(mojoDescriptor)) {
+            return;
+        }
+
+        List<MavenProject> forkedProjects;
+
+        if (mojoDescriptor.isAggregating()) {
+            forkedProjects = session.getProjects();
+        } else {
+            forkedProjects = Collections.singletonList(project);
+        }
+
+        for (MavenProject forkedProject : forkedProjects) {
+            List<MojoExecution> forkedExecutions;
+
+            if (StringUtils.isNotEmpty(mojoDescriptor.getExecutePhase())) {
+                forkedExecutions =
+                        calculateForkedLifecycle(mojoExecution, session, forkedProject, alreadyForkedExecutions);
+            } else {
+                forkedExecutions = calculateForkedGoal(mojoExecution, session, forkedProject, alreadyForkedExecutions);
+            }
+
+            mojoExecution.setForkedExecutions(BuilderCommon.getKey(forkedProject), forkedExecutions);
+        }
+
+        alreadyForkedExecutions.remove(mojoDescriptor);
+    }
+
+    private List<MojoExecution> calculateForkedLifecycle(MojoExecution mojoExecution, MavenSession session,
+                                                         MavenProject project,
+                                                         Collection<MojoDescriptor> alreadyForkedExecutions)
+            throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
+            PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+            LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException {
+        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
+
+        String forkedPhase = mojoDescriptor.getExecutePhase();
+
+        Map<String, List<MojoExecution>> lifecycleMappings = calculateLifecycleMappings(session, project, forkedPhase);
+
+        for (List<MojoExecution> forkedExecutions : lifecycleMappings.values()) {
+            for (MojoExecution forkedExecution : forkedExecutions) {
+                if (forkedExecution.getMojoDescriptor() == null) {
+                    MojoDescriptor forkedMojoDescriptor =
+                            pluginManager.getMojoDescriptor(forkedExecution.getPlugin(), forkedExecution.getGoal(),
+                                    DefaultRepositoryRequest.getRepositoryRequest(session, project));
+
+                    forkedExecution.setMojoDescriptor(forkedMojoDescriptor);
+                }
+
+                populateMojoExecutionConfiguration(project, forkedExecution, false);
+            }
+        }
+
+        injectLifecycleOverlay(lifecycleMappings, mojoExecution, session, project);
+
+        List<MojoExecution> mojoExecutions = new ArrayList<MojoExecution>();
+
+        for (List<MojoExecution> forkedExecutions : lifecycleMappings.values()) {
+            for (MojoExecution forkedExecution : forkedExecutions) {
+                if (!alreadyForkedExecutions.contains(forkedExecution.getMojoDescriptor())) {
+                    finalizeMojoConfiguration(forkedExecution);
+
+                    calculateForkedExecutions(forkedExecution, session, project, alreadyForkedExecutions);
+
+                    mojoExecutions.add(forkedExecution);
+                }
+            }
+        }
+
+        return mojoExecutions;
+    }
+
+    private void injectLifecycleOverlay(Map<String, List<MojoExecution>> lifecycleMappings,
+                                        MojoExecution mojoExecution, MavenSession session, MavenProject project)
+            throws PluginDescriptorParsingException, LifecycleNotFoundException, MojoNotFoundException,
+            PluginNotFoundException, PluginResolutionException, NoPluginFoundForPrefixException,
+            InvalidPluginDescriptorException, PluginVersionResolutionException {
+        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
+
+        PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
+
+        String forkedLifecycle = mojoDescriptor.getExecuteLifecycle();
+
+        if (StringUtils.isEmpty(forkedLifecycle)) {
+            return;
+        }
+
+        org.apache.maven.plugin.lifecycle.Lifecycle lifecycleOverlay;
+
+        try {
+            lifecycleOverlay = pluginDescriptor.getLifecycleMapping(forkedLifecycle);
+        }
+        catch (IOException e) {
+            throw new PluginDescriptorParsingException(pluginDescriptor.getPlugin(), pluginDescriptor.getSource(), e);
+        }
+        catch (XmlPullParserException e) {
+            throw new PluginDescriptorParsingException(pluginDescriptor.getPlugin(), pluginDescriptor.getSource(), e);
+        }
+
+        if (lifecycleOverlay == null) {
+            throw new LifecycleNotFoundException(forkedLifecycle);
+        }
+
+        for (Phase phase : lifecycleOverlay.getPhases()) {
+            List<MojoExecution> forkedExecutions = lifecycleMappings.get(phase.getId());
+
+            if (forkedExecutions != null) {
+                for (Execution execution : phase.getExecutions()) {
+                    for (String goal : execution.getGoals()) {
+                        MojoDescriptor forkedMojoDescriptor;
+
+                        if (goal.indexOf(':') < 0) {
+                            forkedMojoDescriptor = pluginDescriptor.getMojo(goal);
+                            if (forkedMojoDescriptor == null) {
+                                throw new MojoNotFoundException(goal, pluginDescriptor);
+                            }
+                        } else {
+                            forkedMojoDescriptor = mojoDescriptorCreator.getMojoDescriptor(goal, session, project);
+                        }
+
+                        MojoExecution forkedExecution =
+                                new MojoExecution(forkedMojoDescriptor, mojoExecution.getExecutionId());
+
+                        Xpp3Dom forkedConfiguration = (Xpp3Dom) execution.getConfiguration();
+
+                        forkedExecution.setConfiguration(forkedConfiguration);
+
+                        populateMojoExecutionConfiguration(project, forkedExecution, true);
+
+                        forkedExecutions.add(forkedExecution);
+                    }
+                }
+
+                Xpp3Dom phaseConfiguration = (Xpp3Dom) phase.getConfiguration();
+
+                if (phaseConfiguration != null) {
+                    for (MojoExecution forkedExecution : forkedExecutions) {
+                        Xpp3Dom forkedConfiguration = forkedExecution.getConfiguration();
+
+                        forkedConfiguration = Xpp3Dom.mergeXpp3Dom(phaseConfiguration, forkedConfiguration);
+
+                        forkedExecution.setConfiguration(forkedConfiguration);
+                    }
+                }
+            }
+        }
+    }
+    // org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process
+    //TODO: take repo mans into account as one may be aggregating prefixes of many
+    //TODO: collect at the root of the repository, read the one at the root, and fetch remote if something is missing
+    //      or the user forces the issue
+
+    private List<MojoExecution> calculateForkedGoal(MojoExecution mojoExecution, MavenSession session,
+                                                    MavenProject project,
+                                                    Collection<MojoDescriptor> alreadyForkedExecutions)
+            throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
+            PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+            LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException {
+        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
+
+        PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
+
+        String forkedGoal = mojoDescriptor.getExecuteGoal();
+
+        MojoDescriptor forkedMojoDescriptor = pluginDescriptor.getMojo(forkedGoal);
+        if (forkedMojoDescriptor == null) {
+            throw new MojoNotFoundException(forkedGoal, pluginDescriptor);
+        }
+
+        if (alreadyForkedExecutions.contains(forkedMojoDescriptor)) {
+            return Collections.emptyList();
+        }
+
+        MojoExecution forkedExecution = new MojoExecution(forkedMojoDescriptor, forkedGoal);
+
+        populateMojoExecutionConfiguration(project, forkedExecution, true);
+
+        finalizeMojoConfiguration(forkedExecution);
+
+        calculateForkedExecutions(forkedExecution, session, project, alreadyForkedExecutions);
+
+        return Collections.singletonList(forkedExecution);
+    }
+
+
+}
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
new file mode 100644
index 0000000..9e47043
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.ProjectDependenciesResolver;
+import org.apache.maven.execution.BuildFailure;
+import org.apache.maven.execution.BuildSuccess;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.DefaultLifecycleExecutor;
+import org.apache.maven.lifecycle.LifecycleEventCatapult;
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.logging.Logger;
+
+/**
+ * Builds one or more lifecycles for a full module
+ * @author Benjamin Bentmann
+ * @author Jason van Zyl
+ * @author Kristian Rosenvold (extracted class)
+ */
+@Component( role = LifecycleModuleBuilder.class)
+public class LifecycleModuleBuilder {
+    @Requirement
+    private MojoExecutor mojoExecutor;
+    @Requirement
+    private BuilderCommon builderCommon;
+
+    public void buildProject(MavenSession session, BuildContext buildContext, MavenProject currentProject, TaskSegment taskSegment){
+        boolean isAggregating = taskSegment.isAggregating();
+
+        session.setCurrentProject( currentProject);
+
+        long buildStartTime = System.currentTimeMillis();
+
+        try {
+
+            if ( session.isBlackListed(currentProject) || session.isHalted()) {
+                DefaultLifecycleExecutor.fireEvent(session, null, LifecycleEventCatapult.PROJECT_SKIPPED);
+                return;
+            }
+
+            DefaultLifecycleExecutor.fireEvent(session, null, LifecycleEventCatapult.PROJECT_STARTED);
+
+
+            BuilderCommon.attachToThread( currentProject);
+            MavenExecutionPlan executionPlan = builderCommon.resolveBuildPlan( session, currentProject, taskSegment);
+
+            DependencyContext dependencyContext = new DependencyContext(executionPlan, isAggregating);
+            for (ExecutionPlanItem item : executionPlan) {
+                mojoExecutor.execute(session, item.getMojoExecution(), buildContext.getProjectIndex(), dependencyContext);
+            }
+
+            long buildEndTime = System.currentTimeMillis();
+
+            buildContext.getResult().addBuildSummary(new BuildSuccess(currentProject, buildEndTime - buildStartTime));
+
+            DefaultLifecycleExecutor.fireEvent(session, null, LifecycleEventCatapult.PROJECT_SUCCEEDED);
+        }
+        catch (Exception e) {
+            BuilderCommon.handleBuildError( buildContext.getResult(), session, currentProject, e, buildStartTime);
+        }
+        finally {
+            session.setCurrentProject(null);
+            
+            Thread.currentThread().setContextClassLoader(buildContext.getOldContextClassLoader());
+        }
+    }
+}
\ No newline at end of file
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecyclePluginAnalyzerImpl.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecyclePluginAnalyzerImpl.java
new file mode 100644
index 0000000..c73f97b
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecyclePluginAnalyzerImpl.java
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.lifecycle.DefaultLifecycles;
+import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer;
+import org.apache.maven.lifecycle.Lifecycle;
+import org.apache.maven.lifecycle.mapping.LifecycleMapping;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginExecution;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.util.StringUtils;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+  *  
+  * @author Benjamin Bentmann
+  * @author Jason van Zyl
+  * @author jdcasey
+  * @author Kristian Rosenvold (extracted class only)
+  */
+@Component(role = LifecyclePluginAnalyzerImpl.class)
+public class LifecyclePluginAnalyzerImpl implements LifeCyclePluginAnalyzer {
+    @Requirement
+    private Map<String, LifecycleMapping> lifecycleMappings;
+    @Requirement
+    private DefaultLifecycles defaultLifeCycles;
+
+    public LifecyclePluginAnalyzerImpl() {
+    }
+
+
+    // These methods deal with construction intact Plugin object that look like they come from a standard
+    // <plugin/> block in a Maven POM. We have to do some wiggling to pull the sources of information
+    // together and this really shows the problem of constructing a sensible default configuration but
+    // it's all encapsulated here so it appears normalized to the POM builder.
+
+    // We are going to take the project packaging and find all plugin in the default lifecycle and create
+    // fully populated Plugin objects, including executions with goals and default configuration taken
+    // from the plugin.xml inside a plugin.
+    //
+    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging)
+    {
+        LifecycleMapping lifecycleMappingForPackaging = lifecycleMappings.get( packaging );
+
+        if ( lifecycleMappingForPackaging == null )
+        {
+            return null;
+        }
+
+        Map<Plugin, Plugin> plugins = new LinkedHashMap<Plugin, Plugin>();
+
+        for ( Lifecycle lifecycle : defaultLifeCycles.getLifeCycles() )
+        {
+            org.apache.maven.lifecycle.mapping.Lifecycle lifecycleConfiguration =
+                lifecycleMappingForPackaging.getLifecycles().get( lifecycle.getId() );
+
+            Map<String, String> phaseToGoalMapping = null;
+
+            if ( lifecycleConfiguration != null )
+            {
+                phaseToGoalMapping = lifecycleConfiguration.getPhases();
+            }
+            else if ( lifecycle.getDefaultPhases() != null )
+            {
+                phaseToGoalMapping = lifecycle.getDefaultPhases();
+            }
+
+            if ( phaseToGoalMapping != null )
+            {
+                // These are of the form:
+                //
+                // compile -> org.apache.maven.plugins:maven-compiler-plugin:compile[,gid:aid:goal,...]
+                //
+                for ( Map.Entry<String, String> goalsForLifecyclePhase : phaseToGoalMapping.entrySet() )
+                {
+                    String phase = goalsForLifecyclePhase.getKey();
+                    String goals = goalsForLifecyclePhase.getValue();
+                    if ( goals != null )
+                    {
+                        parseLifecyclePhaseDefinitions( plugins, phase, goals );
+                    }
+                }
+            }
+        }
+
+        return plugins.keySet();
+    }
+
+    private void parseLifecyclePhaseDefinitions( Map<Plugin, Plugin> plugins, String phase, String goals )
+    {
+        String[] mojos = StringUtils.split( goals, "," );
+
+        for ( int i = 0; i < mojos.length; i++ )
+        {
+            // either <groupId>:<artifactId>:<goal> or <groupId>:<artifactId>:<version>:<goal>
+            String goal = mojos[i].trim();
+            String[] p = StringUtils.split( goal, ":" );
+
+            PluginExecution execution = new PluginExecution();
+            execution.setId( "default-" + p[p.length - 1] );
+            execution.setPhase( phase );
+            execution.setPriority( i - mojos.length );
+            execution.getGoals().add( p[p.length - 1] );
+
+            Plugin plugin = new Plugin();
+            plugin.setGroupId( p[0] );
+            plugin.setArtifactId( p[1] );
+            if ( p.length >= 4 )
+            {
+                plugin.setVersion( p[2] );
+            }
+
+            Plugin existing = plugins.get( plugin );
+            if ( existing != null )
+            {
+                plugin = existing;
+            }
+            else
+            {
+                plugins.put( plugin, plugin );
+            }
+
+            plugin.getExecutions().add( execution );
+        }
+    }
+    
+
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTask.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTask.java
new file mode 100644
index 0000000..d815088
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTask.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+/**
+ * A task that is a lifecycle
+ *
+ * @author Benjamin Bentmann
+ */
+public final class LifecycleTask
+{
+
+    private final String lifecyclePhase;
+
+    public LifecycleTask( String lifecyclePhase )
+    {
+        this.lifecyclePhase = lifecyclePhase;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getLifecyclePhase();
+    }
+
+    public String getLifecyclePhase() {
+        return lifecyclePhase;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculator.java
new file mode 100644
index 0000000..51d25e9
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculator.java
@@ -0,0 +1,15 @@
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+
+import java.util.List;
+
+public interface LifecycleTaskSegmentCalculator {
+    List<TaskSegment> calculateTaskSegments(MavenSession session, List<String> tasks)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+            MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+            PluginVersionResolutionException;
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculatorImpl.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculatorImpl.java
new file mode 100644
index 0000000..0b1c057
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculatorImpl.java
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Calculates the task segments in the build
+ *
+ * @author Benjamin Bentmann
+ * @author Jason van Zyl
+ * @author jdcasey
+ * @author Kristian Rosenvold (extracted class)
+ */
+
+@Component( role = LifecycleTaskSegmentCalculator.class)
+public class LifecycleTaskSegmentCalculatorImpl implements LifecycleTaskSegmentCalculator {
+    @Requirement
+    private MojoDescriptorCreator mojoDescriptorCreator;
+    
+
+    public LifecycleTaskSegmentCalculatorImpl() {
+    }
+
+    public List<TaskSegment> calculateTaskSegments(MavenSession session, List<String> tasks)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+            MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+            PluginVersionResolutionException {
+        List<TaskSegment> taskSegments = new ArrayList<TaskSegment>(tasks.size());
+
+        TaskSegment currentSegment = null;
+
+        for (String task : tasks) {
+            if (isGoalSpecification(task)) {
+                // "pluginPrefix:goal" or "groupId:artifactId[:version]:goal"
+
+                MojoDescriptor mojoDescriptor = mojoDescriptorCreator.getMojoDescriptor(task, session, session.getTopLevelProject());
+
+                boolean aggregating = mojoDescriptor.isAggregating();
+
+                if (currentSegment == null || currentSegment.isAggregating() != aggregating) {
+                    currentSegment = new TaskSegment(aggregating);
+                    taskSegments.add(currentSegment);
+                }
+
+                currentSegment.getTasks().add(new GoalTask(mojoDescriptor));
+            } else {
+                // lifecycle phase
+
+                if (currentSegment == null || currentSegment.isAggregating()) {
+                    currentSegment = new TaskSegment(false);
+                    taskSegments.add(currentSegment);
+                }
+
+                currentSegment.getTasks().add(new LifecycleTask(task));
+            }
+        }
+
+        return taskSegments;
+    }
+
+    private boolean isGoalSpecification(String task) {
+        return task.indexOf(':') >= 0;
+    }
+
+}
\ No newline at end of file
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilder.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilder.java
new file mode 100644
index 0000000..09fcd93
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilder.java
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.execution.BuildSuccess;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.*;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+
+import java.util.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+/**
+ * Builds the full lifecycle in weave-mode (phase by phase as opposed to project-by-project)
+ *
+ * @author Kristian Rosenvold
+ *         Builds one or more lifecycles for a full module
+ */
+@Component(role = LifecycleWeaveBuilder.class)
+public class LifecycleWeaveBuilder {
+    @Requirement
+    private MojoExecutor mojoExecutor;
+    @Requirement
+    private BuilderCommon builderCommon;
+
+    private final Map<MavenProject, MavenExecutionPlan> executionPlans = Collections.synchronizedMap(new HashMap<MavenProject, MavenExecutionPlan>());
+
+
+    @SuppressWarnings({"UnusedDeclaration"})
+    public LifecycleWeaveBuilder() {
+    }
+
+    public LifecycleWeaveBuilder(MojoExecutor mojoExecutor) {
+        this.mojoExecutor = mojoExecutor;
+    }
+
+    public LifecycleWeaveBuilder(MojoExecutor mojoExecutor, BuilderCommon builderCommon) {
+        this.mojoExecutor = mojoExecutor;
+        this.builderCommon = builderCommon;
+    }
+
+    public void buildProject(ProjectBuildList projectBuilds,
+                             BuildContext buildContext,
+                             MavenSession session,
+                             CompletionService<ProjectBuild> service,
+                             final boolean canScheduleAggressively) throws ExecutionException, InterruptedException {
+        try {
+            final List<Future<ProjectBuild>> futures = new ArrayList<Future<ProjectBuild>>();
+
+            for (ProjectBuildList segmentChunks : projectBuilds.getByTaskSegments()) {
+                ThreadOutputMuxer muxer = new ThreadOutputMuxer(segmentChunks, System.out);
+                for (ProjectBuild projectBuild : segmentChunks) {
+                    MavenExecutionPlan executionPlan;
+                    try {
+                        executionPlan = builderCommon.resolveBuildPlan(projectBuild);
+                        executionPlans.put(projectBuild.getProject(), executionPlan);
+                        DependencyContext dependencyContext = new DependencyContext(executionPlan,
+                                                                    projectBuild.getTaskSegment().isAggregating());
+
+
+                        final Callable<ProjectBuild> projectBuilder = createCallableForBuildingOneFullModule(service,
+                                buildContext, session, executionPlan, projectBuild, canScheduleAggressively, muxer, dependencyContext);
+
+                        futures.add( service.submit(projectBuilder));
+                    } catch (Exception e) {
+                        throw new ExecutionException(e);
+                    }
+                }
+
+                for (Future<ProjectBuild> buildFuture : futures) {
+                    buildFuture.get();  // At this point, this build *is* finished.
+                                        // Do not leak threads past here or evil gremlins will get you!
+                }
+                futures.clear();
+            }
+        } finally {
+            projectBuilds.closeAll();
+        }
+    }
+
+    private Callable<ProjectBuild> createCallableForBuildingOneFullModule(
+            final CompletionService<ProjectBuild> service,
+            final BuildContext buildContext,
+            final MavenSession rootSession,
+            final MavenExecutionPlan executionPlan,
+            final ProjectBuild projectBuild,
+            final boolean canScheduleAggressively,
+            final ThreadOutputMuxer muxer,
+            final DependencyContext dependencyContext
+    ) {
+        return new Callable<ProjectBuild>() {
+            final List<Future<ProjectBuild>> aggressiveSchedules = new ArrayList<Future<ProjectBuild>>();
+
+
+            public ProjectBuild call() throws Exception {
+
+                Iterator<ExecutionPlanItem> planItems = executionPlan.iterator();
+                ExecutionPlanItem current = planItems.hasNext() ? planItems.next() : null;
+                long buildStartTime = System.currentTimeMillis();
+                long waitingTime = 0;
+
+                muxer.associateThreadWithProjectBuild(projectBuild);
+
+                if (projectBuild.isHaltedOrBlacklisted()) {
+                    DefaultLifecycleExecutor.fireEvent(projectBuild.getSession(), null, LifecycleEventCatapult.PROJECT_SKIPPED);
+                    return null;
+                }
+
+                DefaultLifecycleExecutor.fireEvent(projectBuild.getSession(), null, LifecycleEventCatapult.PROJECT_STARTED);
+
+                try {
+                    while (current != null && !rootSession.isHalted() && !rootSession.isBlackListed(projectBuild.getProject())) {
+                        final Schedule schedule = current.getSchedule();
+                        if (schedule != null && schedule.isMojoSynchronized()) {
+                            synchronized (current.getPlugin()) {
+                                buildExecutionPlanItem(buildContext, current, projectBuild, dependencyContext);
+                            }
+                        } else {
+                            buildExecutionPlanItem(buildContext, current, projectBuild, dependencyContext);
+                        }
+
+                        current.setComplete();
+
+                        ExecutionPlanItem next = planItems.hasNext() ? planItems.next() : null;
+                        if (next != null) {
+                            final Schedule scheduleOfNext = next.getSchedule();
+                            if (scheduleOfNext != null) {
+                                if (scheduleOfNext.isForkable() && canScheduleAggressively) {
+                                    final Callable<ProjectBuild> projectBuildCallable = createForkedCallable(buildContext,
+                                            rootSession, next, projectBuild, muxer, dependencyContext, buildStartTime);
+                                    aggressiveSchedules.add(service.submit(projectBuildCallable));
+                                    next = planItems.hasNext() ? planItems.next() : null;
+                                } else if (scheduleOfNext.isOutputDependant()) {
+                                    for (MavenProject upstreamProject : projectBuild.getImmediateUpstreamProjects()) {
+                                        final MavenExecutionPlan upstreamPlan = executionPlans.get(upstreamProject);
+                                        final ExecutionPlanItem inSchedule = upstreamPlan.findFirstWithMatchingSchedule(scheduleOfNext);
+                                        if (inSchedule != null) {
+                                            long startWait = System.currentTimeMillis();
+                                            inSchedule.waitUntilDone();
+                                            waitingTime += (System.currentTimeMillis() - startWait);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        current = next;
+                    }
+                    for (Future<ProjectBuild> aggressiveSchedule : aggressiveSchedules) {
+                        aggressiveSchedule.get();
+                    }
+
+                    final long wallClockTime = System.currentTimeMillis() - buildStartTime;
+                    final BuildSuccess summary = new BuildSuccess(projectBuild.getProject(), wallClockTime - waitingTime);
+                    buildContext.getResult().addBuildSummary(summary);
+                    DefaultLifecycleExecutor.fireEvent(projectBuild.getSession(), null, LifecycleEventCatapult.PROJECT_SUCCEEDED);
+
+                } catch (Exception e) {
+                    BuilderCommon.handleBuildError(buildContext.getResult(), rootSession, projectBuild.getProject(), e, buildStartTime);
+                } finally {
+                    if (current != null) executionPlan.forceAllComplete();
+                    muxer.setThisModuleComplete(projectBuild);
+                }
+                return null;
+            }
+        };
+    }
+
+    private Callable<ProjectBuild> createForkedCallable(final BuildContext buildContext,
+                                                        final MavenSession rootSession,
+                                                        final ExecutionPlanItem current,
+                                                        final ProjectBuild projectBuild,
+                                                        final ThreadOutputMuxer muxer,
+                                                        final DependencyContext dependencyContext,
+                                                        final long buildStartTime) {
+        return new Callable<ProjectBuild>() {
+            public ProjectBuild call() throws Exception {
+                try {
+                    muxer.setThisModuleComplete(projectBuild);
+                    buildExecutionPlanItem(buildContext, current, projectBuild, dependencyContext);
+                    current.setComplete();
+                } catch (Exception e) {
+                    BuilderCommon.handleBuildError(buildContext.getResult(), rootSession, projectBuild.getProject(), e, buildStartTime);
+                    throw e;
+                } finally {
+                    muxer.disconnectThreadFromProject();
+                }
+                return projectBuild;
+            }
+        };
+    }
+
+    private void buildExecutionPlanItem(BuildContext buildContext,
+                                        ExecutionPlanItem node,
+                                        ProjectBuild projectBuild,
+                                        DependencyContext dependencyContext) throws LifecycleExecutionException {
+
+        MavenProject currentProject = projectBuild.getProject();
+
+
+        long buildStartTime = System.currentTimeMillis();
+
+        MavenSession sessionForThisModule = projectBuild.getSession();
+        try {
+
+            if (projectBuild.isHaltedOrBlacklisted()) {
+                DefaultLifecycleExecutor.fireEvent(sessionForThisModule, null, LifecycleEventCatapult.PROJECT_SKIPPED);
+                return;
+            }
+
+            BuilderCommon.attachToThread(currentProject);
+
+            mojoExecutor.execute(sessionForThisModule,
+                                 node.getMojoExecution(),
+                                 buildContext.getProjectIndex(),
+                                 dependencyContext);
+            long buildEndTime = System.currentTimeMillis();
+
+            buildContext.getResult().addBuildSummary(new BuildSuccess(currentProject, buildEndTime - buildStartTime));
+
+            DefaultLifecycleExecutor.fireEvent(sessionForThisModule, null, LifecycleEventCatapult.PROJECT_SUCCEEDED);
+        }
+        finally {
+            Thread.currentThread().setContextClassLoader(buildContext.getOldContextClassLoader());
+        }
+    }
+
+
+}
\ No newline at end of file
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoDescriptorCreator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoDescriptorCreator.java
new file mode 100644
index 0000000..47510db
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoDescriptorCreator.java
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.artifact.repository.DefaultRepositoryRequest;
+import org.apache.maven.artifact.repository.RepositoryRequest;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.prefix.*;
+import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
+import org.apache.maven.plugin.version.PluginVersionRequest;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+import org.apache.maven.plugin.version.PluginVersionResolver;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.StringTokenizer;
+
+/**
+ * Resolves dependencies for the artifacts in context of the lifecycle build
+ *
+ * @author Benjamin Bentmann
+ * @author Jason van Zyl
+ * @author jdcasey
+ * @author Kristian Rosenvold (extracted class only)
+ */
+
+@Component(role = MojoDescriptorCreator.class)
+public class MojoDescriptorCreator {
+    @Requirement
+    private PluginVersionResolver pluginVersionResolver;
+    @Requirement
+    private BuildPluginManager pluginManager;
+    @Requirement
+    private PluginPrefixResolver pluginPrefixResolver;
+
+    public MojoDescriptorCreator() {
+    }
+
+    public MojoDescriptorCreator(PluginVersionResolver pluginVersionResolver, BuildPluginManager pluginManager, PluginPrefixResolver pluginPrefixResolver) {
+        this.pluginVersionResolver = pluginVersionResolver;
+        this.pluginManager = pluginManager;
+        this.pluginPrefixResolver = pluginPrefixResolver;
+    }
+
+    private Plugin findPlugin(String groupId, String artifactId, Collection<Plugin> plugins) {
+        for (Plugin plugin : plugins) {
+            if (artifactId.equals(plugin.getArtifactId()) && groupId.equals(plugin.getGroupId())) {
+                return plugin;
+            }
+        }
+
+        return null;
+    }
+
+    public static Xpp3Dom convert(MojoDescriptor mojoDescriptor) {
+        Xpp3Dom dom = new Xpp3Dom("configuration");
+
+        PlexusConfiguration c = mojoDescriptor.getMojoConfiguration();
+
+        PlexusConfiguration[] ces = c.getChildren();
+
+        if (ces != null) {
+            for (PlexusConfiguration ce : ces) {
+                String value = ce.getValue(null);
+                String defaultValue = ce.getAttribute("default-value", null);
+                if (value != null || defaultValue != null) {
+                    Xpp3Dom e = new Xpp3Dom(ce.getName());
+                    e.setValue(value);
+                    if (defaultValue != null) {
+                        e.setAttribute("default-value", defaultValue);
+                    }
+                    dom.addChild(e);
+                }
+            }
+        }
+
+        return dom;
+    }
+
+    // org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process
+
+    public MojoDescriptor getMojoDescriptor(String task, MavenSession session, MavenProject project)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException, PluginVersionResolutionException {
+        String goal = null;
+
+        Plugin plugin = null;
+
+        StringTokenizer tok = new StringTokenizer(task, ":");
+
+        int numTokens = tok.countTokens();
+
+        if (numTokens == 4) {
+            // We have everything that we need
+            //
+            // org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process
+            //
+            // groupId
+            // artifactId
+            // version
+            // goal
+            //
+            plugin = new Plugin();
+            plugin.setGroupId(tok.nextToken());
+            plugin.setArtifactId(tok.nextToken());
+            plugin.setVersion(tok.nextToken());
+            goal = tok.nextToken();
+
+        } else if (numTokens == 3) {
+            // We have everything that we need except the version
+            //
+            // org.apache.maven.plugins:maven-remote-resources-plugin:???:process
+            //
+            // groupId
+            // artifactId
+            // ???
+            // goal
+            //
+            plugin = new Plugin();
+            plugin.setGroupId(tok.nextToken());
+            plugin.setArtifactId(tok.nextToken());
+            goal = tok.nextToken();
+        } else if (numTokens == 2) {
+            // We have a prefix and goal
+            //
+            // idea:idea
+            //
+            String prefix = tok.nextToken();
+            goal = tok.nextToken();
+
+            // This is the case where someone has executed a single goal from the command line
+            // of the form:
+            //
+            // mvn remote-resources:process
+            //
+            // From the metadata stored on the server which has been created as part of a standard
+            // Maven plugin deployment we will find the right PluginDescriptor from the remote
+            // repository.
+
+            plugin = findPluginForPrefix(prefix, session);
+        }
+
+        injectPluginDeclarationFromProject(plugin, project);
+
+        RepositoryRequest repositoryRequest = DefaultRepositoryRequest.getRepositoryRequest(session, project);
+
+        // If there is no version to be found then we need to look in the repository metadata for
+        // this plugin and see what's specified as the latest release.
+        //
+        if (plugin.getVersion() == null) {
+            resolvePluginVersion(plugin, repositoryRequest);
+        }
+
+        return pluginManager.getMojoDescriptor(plugin, goal, repositoryRequest);
+    }
+    //TODO: take repo mans into account as one may be aggregating prefixes of many
+    //TODO: collect at the root of the repository, read the one at the root, and fetch remote if something is missing
+    //      or the user forces the issue
+
+    public Plugin findPluginForPrefix(String prefix, MavenSession session)
+            throws NoPluginFoundForPrefixException {
+        // [prefix]:[goal]
+
+        PluginPrefixRequest prefixRequest = new DefaultPluginPrefixRequest(prefix, session);
+        PluginPrefixResult prefixResult = pluginPrefixResolver.resolve(prefixRequest);
+
+        Plugin plugin = new Plugin();
+        plugin.setGroupId(prefixResult.getGroupId());
+        plugin.setArtifactId(prefixResult.getArtifactId());
+
+        return plugin;
+    }
+
+    private void resolvePluginVersion(Plugin plugin, RepositoryRequest repositoryRequest)
+            throws PluginVersionResolutionException {
+        PluginVersionRequest versionRequest = new DefaultPluginVersionRequest(plugin, repositoryRequest);
+        plugin.setVersion(pluginVersionResolver.resolve(versionRequest).getVersion());
+    }
+
+
+    private void injectPluginDeclarationFromProject(Plugin plugin, MavenProject project) {
+        Plugin pluginInPom = findPlugin(plugin, project.getBuildPlugins());
+
+        if (pluginInPom == null && project.getPluginManagement() != null) {
+            pluginInPom = findPlugin(plugin, project.getPluginManagement().getPlugins());
+        }
+
+        if (pluginInPom != null) {
+            if (plugin.getVersion() == null) {
+                plugin.setVersion(pluginInPom.getVersion());
+            }
+
+            plugin.setDependencies(new ArrayList<Dependency>(pluginInPom.getDependencies()));
+        }
+    }
+
+    private Plugin findPlugin(Plugin plugin, Collection<Plugin> plugins) {
+        return findPlugin(plugin.getGroupId(), plugin.getArtifactId(), plugins);
+    }
+
+
+}
+
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
new file mode 100644
index 0000000..7faf593
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.DefaultLifecycleExecutor;
+import org.apache.maven.lifecycle.LifecycleEventCatapult;
+import org.apache.maven.lifecycle.LifecycleExecutionException;
+import org.apache.maven.plugin.*;
+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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Executes an individual mojo
+ * @author Jason van Zyl
+ * @author Benjamin Bentmann
+ * @author Kristian Rosenvold
+ */
+@Component( role = MojoExecutor.class)
+public class MojoExecutor {
+
+    @Requirement
+    private BuildPluginManager pluginManager;
+
+    @Requirement
+    private LifecycleDependencyResolver lifeCycleDependencyResolver;
+
+    public MojoExecutor() {
+    }
+
+    @SuppressWarnings({"ThrowableInstanceNeverThrown"})
+    public void execute(MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex,
+                        DependencyContext dependencyContext)
+        throws LifecycleExecutionException
+    {
+        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
+
+        if ( mojoDescriptor.isProjectRequired() && !session.isUsingPOMsFromFilesystem() )
+        {
+            Throwable cause =
+                new IllegalStateException( "Goal requires a project to execute but there is no POM in this build." );
+            throw new LifecycleExecutionException( mojoExecution, null, cause );
+        }
+
+        if ( mojoDescriptor.isOnlineRequired() && session.isOffline() )
+        {
+            if ( MojoExecution.Source.CLI.equals( mojoExecution.getSource() ) )
+            {
+                Throwable cause =
+                    new IllegalStateException( "Goal requires online mode for execution"
+                        + " but Maven is currently offline." );
+                throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), cause );
+            }
+            else
+            {
+                DefaultLifecycleExecutor.fireEvent(session, mojoExecution, LifecycleEventCatapult.MOJO_SKIPPED );
+
+                return;
+            }
+        }
+
+        lifeCycleDependencyResolver.checkForUpdate( session, dependencyContext );
+
+        List<MavenProject> forkedProjects = executeForkedExecutions( mojoExecution, session, projectIndex, dependencyContext);
+
+        DefaultLifecycleExecutor.fireEvent(session, mojoExecution, LifecycleEventCatapult.MOJO_STARTED );
+        try {
+            try {
+                pluginManager.executeMojo(session, mojoExecution);
+
+                DefaultLifecycleExecutor.fireEvent(session, mojoExecution, LifecycleEventCatapult.MOJO_SUCCEEDED);
+            }
+            catch (MojoFailureException e) {
+                throw new LifecycleExecutionException(mojoExecution, session.getCurrentProject(), e);
+            }
+            catch (MojoExecutionException e) {
+                throw new LifecycleExecutionException(mojoExecution, session.getCurrentProject(), e);
+            }
+            catch (PluginConfigurationException e) {
+                throw new LifecycleExecutionException(mojoExecution, session.getCurrentProject(), e);
+            }
+            catch (PluginManagerException e) {
+                throw new LifecycleExecutionException(mojoExecution, session.getCurrentProject(), e);
+            }
+
+            DefaultLifecycleExecutor.fireEvent(session, mojoExecution, LifecycleEventCatapult.MOJO_SUCCEEDED);
+        }
+        catch (LifecycleExecutionException e) {
+            DefaultLifecycleExecutor.fireEvent(session, mojoExecution, LifecycleEventCatapult.MOJO_FAILED);
+
+            throw e;
+        }
+        finally {
+            for (MavenProject forkedProject : forkedProjects) {
+                forkedProject.setExecutionProject(null);
+            }
+        }
+    }
+
+    private List<MavenProject> executeForkedExecutions(MojoExecution mojoExecution, MavenSession session,
+                                                       ProjectIndex projectIndex, DependencyContext dependencyContext)
+        throws LifecycleExecutionException
+    {
+        List<MavenProject> forkedProjects = Collections.emptyList();
+
+        Map<String, List<MojoExecution>> forkedExecutions = mojoExecution.getForkedExecutions();
+
+        if ( !forkedExecutions.isEmpty() )
+        {
+            DefaultLifecycleExecutor.fireEvent(session, mojoExecution, LifecycleEventCatapult.FORK_STARTED );
+
+            MavenProject project = session.getCurrentProject();
+
+            forkedProjects = new ArrayList<MavenProject>( forkedExecutions.size() );
+
+            dependencyContext = dependencyContext.clone();
+
+            try
+            {
+                for ( Map.Entry<String, List<MojoExecution>> fork : forkedExecutions.entrySet() )
+                {
+                    int index = projectIndex.getIndices().get( fork.getKey() );
+
+                    MavenProject forkedProject = projectIndex.getProjects().get( fork.getKey() );
+
+                    forkedProjects.add( forkedProject );
+
+                    MavenProject executedProject = forkedProject.clone();
+
+                    forkedProject.setExecutionProject( executedProject );
+
+                    try
+                    {
+                        session.setCurrentProject( executedProject );
+                        session.getProjects().set( index, executedProject );
+                        projectIndex.getProjects().put( fork.getKey(), executedProject );
+
+                        for ( MojoExecution forkedExecution : fork.getValue() )
+                        {
+                            execute( session, forkedExecution, projectIndex, dependencyContext);
+                        }
+                    }
+                    finally
+                    {
+                        projectIndex.getProjects().put( fork.getKey(), forkedProject );
+                        session.getProjects().set( index, forkedProject );
+                        session.setCurrentProject( project );
+                    }
+                }
+
+                DefaultLifecycleExecutor.fireEvent(session, mojoExecution, LifecycleEventCatapult.FORK_SUCCEEDED );
+            }
+            catch ( LifecycleExecutionException e )
+            {
+                DefaultLifecycleExecutor.fireEvent(session, mojoExecution, LifecycleEventCatapult.FORK_FAILED );
+
+                throw e;
+            }
+        }
+
+        return forkedProjects;
+    }
+
+
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectBuild.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectBuild.java
new file mode 100644
index 0000000..3b01590
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectBuild.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.execution.ProjectDependencyGraph;
+import org.apache.maven.project.MavenProject;
+
+import java.util.List;
+
+/**
+ * A build context that matches a mavenproject to a given tasksegment, and the session to be used.
+ *
+ * A note to the reader;
+ *
+ * There are several issues/discussions regarding how "aggregator" plugins should be handled.
+ * Read for instance http://docs.codehaus.org/display/MAVEN/Deterministic+Lifecycle+Planning
+ *
+ * In their current implementation they are "bolted" onto the lifecycle by separating them
+ * into TaskSegments. This class represents the execution context of one such task segment.
+ *
+ * Wise voices have suggested that maybe aggregators shouldn't be bound to the ordinary
+ * lifecycle at all, in which case we wouldn't be needing this class at all ( and
+ * ProjectBuildList.getByTaskSegments). Or maybe they should be introduced in the calculation
+ * of the execution plan instead, which seems much nicer.
+ *
+ * Additionally this class contains a clone of the MavenSession, which is *only* needed
+ * because it has as notion of a "current" project.
+ *
+ * @author Jason van Zyl
+ * @author Benjamin Bentmann
+ * @author Kristian Rosenvold
+ */
+public final class ProjectBuild {
+    private final MavenProject project;
+    private final TaskSegment taskSegment;
+    private final MavenSession session;
+
+
+    public ProjectBuild(MavenProject project, TaskSegment taskSegment, MavenSession copiedSession) {
+        this.project = project;
+        this.taskSegment = taskSegment;
+        this.session = copiedSession;
+    }
+
+    public MavenSession getSession() {
+        return session;
+    }
+
+    public MavenProject getProject() {
+        return project;
+    }
+
+    public TaskSegment getTaskSegment() {
+        return taskSegment;
+    }
+
+    public List<MavenProject> getImmediateUpstreamProjects() {
+        final ProjectDependencyGraph dependencyGraph = getSession().getProjectDependencyGraph();
+        return dependencyGraph.getUpstreamProjects(getProject(), false);
+    }
+
+
+    @Override
+    public String toString() {
+        return getProject().getId() + " -> " + getTaskSegment();
+    }
+
+    public boolean isHaltedOrBlacklisted(){
+         return session.isBlackListed(project) || session.isHalted();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectBuildList.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectBuildList.java
new file mode 100644
index 0000000..add775b
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectBuildList.java
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+
+import java.util.*;
+
+/**
+ * A list of project builds
+ * @author Kristian Rosenvold
+ */
+public class ProjectBuildList implements Iterable<ProjectBuild> {
+    private final List<ProjectBuild> items;
+    private final List<ProjectBuild> lastInTaskSegment;
+    private final Map<MavenProject, ProjectBuild> byMavenProject = new HashMap<MavenProject, ProjectBuild>();
+
+
+    public ProjectBuildList(List<ProjectBuild> items) {
+        this (items, Collections.<ProjectBuild>emptyList());
+    }
+
+    public ProjectBuildList(List<ProjectBuild> items, List<ProjectBuild> lastInTaskSegment) {
+        this.items = Collections.unmodifiableList( items);
+        this.lastInTaskSegment = lastInTaskSegment;
+        for (ProjectBuild item : items) {
+            byMavenProject.put(item.getProject(), item);
+        }
+    }
+
+    public List<ProjectBuildList> getByTaskSegments(){
+        List<ProjectBuildList> result = new ArrayList<ProjectBuildList>();
+        Iterator<ProjectBuild> taskSegments  = lastInTaskSegment.iterator();
+
+        ProjectBuild lastInSegment = taskSegments.hasNext() ? taskSegments.next() : null;
+        List<ProjectBuild> currentSegment = new ArrayList<ProjectBuild>();
+        for ( ProjectBuild projectBuild : items){
+            currentSegment.add( projectBuild);
+            if ( projectBuild.equals( lastInSegment)){
+                 result.add( new ProjectBuildList(currentSegment));
+                 currentSegment = new ArrayList<ProjectBuild>();
+                 lastInSegment = taskSegments.hasNext() ? taskSegments.next() : null;
+            }
+        }
+        result.add( new ProjectBuildList(currentSegment));
+        return result;
+    }
+
+    public int sizeOfLargestBuildList(){
+        int biggest = 0;
+        for (ProjectBuildList projectBuildList : getByTaskSegments()) {
+            biggest = Math.max( biggest, projectBuildList.size());
+        }
+        return biggest;
+    }
+
+    public Iterator<ProjectBuild> iterator() {
+        return items.iterator();
+    }
+
+    public ProjectBuild getProjectBuild(MavenProject mavenProject){
+        return byMavenProject.get( mavenProject);
+    }
+
+    public void closeAll() {
+        for (ProjectBuild item : items) {
+            MavenSession sessionForThisModule = item.getSession();
+            sessionForThisModule.setCurrentProject(null);
+        }
+    }
+
+
+    public int size() {
+        return items.size();
+    }
+
+    ProjectBuild get(int index) {
+        return items.get(index);
+    }
+
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectIndex.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectIndex.java
new file mode 100644
index 0000000..9200fb4
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectIndex.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.project.MavenProject;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provides the positional index of the project
+ *
+ * @author Benjamin Bentmann
+ * @author Kristian Rosenvold (extracted class only)
+ */
+// Todo: Kristian wonders if this class really is necessary and if it overlaps other concepts.
+public final class ProjectIndex
+{
+
+    private final Map<String, MavenProject> projects;
+
+    private final Map<String, Integer> indices;
+
+    public ProjectIndex( List<MavenProject> projects )
+    {
+        this.projects = new HashMap<String, MavenProject>( projects.size() * 2 );
+        this.indices = new HashMap<String, Integer>( projects.size() * 2 );
+
+        for ( int i = 0; i < projects.size(); i++ )
+        {
+            MavenProject project = projects.get( i );
+            String key = BuilderCommon.getKey( project );
+
+            this.getProjects().put( key, project );
+            this.getIndices().put( key, Integer.valueOf( i ) );
+        }
+    }
+
+    public Map<String, MavenProject> getProjects() {
+        return projects;
+    }
+
+    public Map<String, Integer> getIndices() {
+        return indices;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/TaskSegment.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/TaskSegment.java
new file mode 100644
index 0000000..e25d57b
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/TaskSegment.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+package org.apache.maven.lifecycle.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Describes the required task segment as provided on the maven command line; i.e. "clean jetty:run install"
+  * @author Benjamin Bentmann
+  * @author Kristian Rosenvold (extracted class only)
+  */
+public final class TaskSegment
+{
+
+    // Can be both "LifeCycleTask" (clean/install) and "GoalTask" (org.mortbay.jetty:maven-jetty-plugin:6.1.19:run)
+    private final List<Object> tasks;
+
+    private final boolean aggregating;
+
+    public TaskSegment( boolean aggregating )
+    {
+        this.aggregating = aggregating;
+        tasks = new ArrayList<Object>();
+    }
+
+    public TaskSegment( boolean aggregating, Object... tasks )
+    {
+        this.aggregating = aggregating;
+        this.tasks = new ArrayList<Object>(Arrays.asList(tasks));
+    }
+
+    @Override
+    public String toString()
+    {
+        return getTasks().toString();
+    }
+
+    public List<Object> getTasks() {
+        return tasks;
+    }
+
+    public boolean isAggregating() {
+        return aggregating;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ThreadOutputMuxer.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ThreadOutputMuxer.java
new file mode 100644
index 0000000..f508ef8
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ThreadOutputMuxer.java
@@ -0,0 +1,349 @@
+package org.apache.maven.lifecycle.internal;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.*;
+
+/**
+ * @author Kristian Rosenvold
+ */
+@SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter"})
+public class ThreadOutputMuxer {
+    private final Iterator<ProjectBuild> projects;
+    private final ThreadLocal<ProjectBuild> projectBuildThreadLocal = new ThreadLocal<ProjectBuild>();
+    private final Map<ProjectBuild, ByteArrayOutputStream> streams = new HashMap<ProjectBuild, ByteArrayOutputStream>();
+    private final Map<ProjectBuild, PrintStream> printStreams = new HashMap<ProjectBuild, PrintStream>();
+    private final ByteArrayOutputStream defaultOutputStreamForUnknownData = new ByteArrayOutputStream();
+    private final PrintStream defaultPringStream = new PrintStream(defaultOutputStreamForUnknownData);
+    private final Set<ProjectBuild> completedBuilds = Collections.synchronizedSet(new HashSet<ProjectBuild>());
+    private volatile ProjectBuild currentBuild;
+    private final PrintStream originalSystemOUtStream;
+    private final ConsolePrinter printer;
+
+    /**
+     * A simple but safe solution for printing to the console.
+     */
+
+    class ConsolePrinter implements Runnable {
+        public volatile boolean running;
+        private final ProjectBuildList projectBuildList;
+
+        ConsolePrinter(ProjectBuildList projectBuildList) {
+            this.projectBuildList = projectBuildList;
+        }
+
+        public void run() {
+            running = true;
+            for (ProjectBuild projectBuild : projectBuildList) {
+                final PrintStream projectStream = printStreams.get(projectBuild);
+                ByteArrayOutputStream projectOs = streams.get(projectBuild);
+
+                do {
+                    synchronized (projectStream) {
+                        try {
+                            projectStream.wait(100);
+                        } catch (InterruptedException e) {
+                            throw new RuntimeException(e);
+                        }
+                        try {
+                            projectOs.writeTo( originalSystemOUtStream);
+                        } catch (IOException e) {
+                            throw new RuntimeException(e);
+                        }
+
+                        projectOs.reset();
+                    }
+                } while (!completedBuilds.contains(projectBuild));
+            }
+            running = false;
+        }
+
+        /*
+        Wait until we are sure the print-stream thread is running.
+         */
+        public void waitUntilRunning(boolean expect) {
+            while (!running == expect) {
+                try {
+                    Thread.sleep(10);
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+
+    public ThreadOutputMuxer(ProjectBuildList segmentChunks, PrintStream originalSystemOut) {
+        projects = segmentChunks.iterator();
+        for (ProjectBuild segmentChunk : segmentChunks) {
+            final ByteArrayOutputStream value = new ByteArrayOutputStream();
+            streams.put(segmentChunk, value);
+            printStreams.put(segmentChunk, new PrintStream(value));
+        }
+        setNext();
+        this.originalSystemOUtStream = originalSystemOut;
+        System.setOut(new ThreadBoundPrintStream(this.originalSystemOUtStream));
+        printer = new ConsolePrinter(segmentChunks);
+        new Thread(printer).start();
+        printer.waitUntilRunning(true);
+    }
+
+    public void close() {
+        printer.waitUntilRunning(false);
+        System.setOut(this.originalSystemOUtStream);
+    }
+
+    private void setNext() {
+        currentBuild = projects.hasNext() ? projects.next() : null;
+    }
+
+    private boolean ownsRealOutputStream(ProjectBuild projectBuild) {
+        return projectBuild.equals(currentBuild);
+    }
+
+    private PrintStream getThreadBoundPrintStream() {
+        ProjectBuild threadProject = projectBuildThreadLocal.get();
+        if (threadProject == null) {
+            return defaultPringStream;
+        }
+        if (ownsRealOutputStream(threadProject))
+            return originalSystemOUtStream;
+        return printStreams.get(threadProject);
+    }
+
+    public void associateThreadWithProjectBuild(ProjectBuild projectBuild) {
+        projectBuildThreadLocal.set(projectBuild);
+    }
+
+    public void setThisModuleComplete(ProjectBuild projectBuild) {
+        completedBuilds.add(projectBuild);
+        PrintStream stream = printStreams.get( projectBuild); 
+        synchronized ( stream){
+            stream.notifyAll();
+        }
+        disconnectThreadFromProject();
+    }
+
+    public void disconnectThreadFromProject() {
+        projectBuildThreadLocal.remove();
+    }
+
+    private class ThreadBoundPrintStream extends PrintStream {
+
+        public ThreadBoundPrintStream(PrintStream systemOutStream) {
+            super(systemOutStream);
+        }
+
+        private PrintStream getOutputStreamForCurrentThread() {
+            return getThreadBoundPrintStream();
+        }
+
+        @Override
+        public void println() {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.println();
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void print(char c) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.print(c);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void println(char x) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.println(x);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void print(double d) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.print(d);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void println(double x) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.println(x);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void print(float f) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.print(f);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void println(float x) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.println(x);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void print(int i) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.print(i);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void println(int x) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.println(x);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void print(long l) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.print(l);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void println(long x) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.print(x);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void print(boolean b) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.print(b);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void println(boolean x) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.print(x);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void print(char s[]) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.print(s);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void println(char x[]) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.print(x);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void print(Object obj) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.print(obj);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void println(Object x) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.println(x);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void print(String s) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.print(s);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void println(String x) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.println(x);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void write(byte b[], int off, int len) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.write(b, off, len);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void close() {
+            getOutputStreamForCurrentThread().close();
+        }
+
+        @Override
+        public void flush() {
+            getOutputStreamForCurrentThread().flush();
+        }
+
+        @Override
+        public void write(int b) {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.write(b);
+                currentStream.notifyAll();
+            }
+        }
+
+        @Override
+        public void write(byte b[]) throws IOException {
+            final PrintStream currentStream = getOutputStreamForCurrentThread();
+            synchronized (currentStream) {
+                currentStream.write(b);
+                currentStream.notifyAll();
+            }
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java
index fcc850b..4cff372 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java
@@ -616,7 +616,7 @@ public class DefaultMavenPluginManager
         }
     }
 
-    private void populatePluginFields( Object mojo, MojoDescriptor mojoDescriptor, ClassRealm pluginRealm,
+    private synchronized void populatePluginFields( Object mojo, MojoDescriptor mojoDescriptor, ClassRealm pluginRealm,
                                        PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator )
         throws PluginConfigurationException
     {
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginManager.java
index 35b169d..a5c1a09 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginManager.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginManager.java
@@ -85,23 +85,6 @@ public class DefaultPluginManager
     @Requirement
     private LegacySupport legacySupport;
 
-    private RepositoryRequest getRepositoryRequest( MavenSession session, MavenProject project )
-    {
-        RepositoryRequest request = new DefaultRepositoryRequest();
-
-        request.setCache( session.getRepositoryCache() );
-        request.setLocalRepository( session.getLocalRepository() );
-        if ( project != null )
-        {
-            request.setRemoteRepositories( project.getPluginArtifactRepositories() );
-        }
-        request.setOffline( session.isOffline() );
-        request.setForceUpdate( session.getRequest().isUpdateSnapshots() );
-        request.setTransferListener( session.getRequest().getTransferListener() );
-
-        return request;
-    }
-
     public void executeMojo( MavenProject project, MojoExecution execution, MavenSession session )
         throws MojoExecutionException, ArtifactResolutionException, MojoFailureException, ArtifactNotFoundException,
         InvalidDependencyVersionException, PluginManagerException, PluginConfigurationException
@@ -117,7 +100,7 @@ public class DefaultPluginManager
         PluginDescriptor pluginDescriptor;
         try
         {
-            RepositoryRequest repositoryRequest = getRepositoryRequest( session, session.getCurrentProject() );
+            RepositoryRequest repositoryRequest = DefaultRepositoryRequest.getRepositoryRequest( session, session.getCurrentProject() );
 
             pluginDescriptor = pluginManager.getPluginDescriptor( plugin, repositoryRequest );
 
@@ -149,7 +132,7 @@ public class DefaultPluginManager
         PluginDescriptor pluginDescriptor;
         try
         {
-            RepositoryRequest repositoryRequest = getRepositoryRequest( session, session.getCurrentProject() );
+            RepositoryRequest repositoryRequest = DefaultRepositoryRequest.getRepositoryRequest( session, session.getCurrentProject() );
 
             pluginDescriptor = pluginManager.getPluginDescriptor( plugin, repositoryRequest );
 
diff --git a/maven-core/src/main/resources/META-INF/plexus/components.xml b/maven-core/src/main/resources/META-INF/plexus/components.xml
index 9d400b7..8d763fd 100644
--- a/maven-core/src/main/resources/META-INF/plexus/components.xml
+++ b/maven-core/src/main/resources/META-INF/plexus/components.xml
@@ -17,103 +17,164 @@
   -->
 <component-set>
   <components>
-    <component>
-      <role>org.apache.maven.plugin.MavenPluginCollector</role>
-      <implementation>org.apache.maven.plugin.MavenPluginCollector
-      </implementation>
-    </component>
-    <component>
-      <role>org.apache.maven.lifecycle.LifecycleExecutor</role>
-      <implementation>org.apache.maven.lifecycle.DefaultLifecycleExecutor
-      </implementation>
-      <requirements>
-        <requirement>
-          <role>org.codehaus.plexus.logging.Logger</role>
-          <role-hint>default</role-hint>
-          <field-name>logger</field-name>
-        </requirement>
-        <requirement>
-          <role>org.apache.maven.plugin.BuildPluginManager</role>
-        </requirement>
-        <requirement>
-          <role>org.apache.maven.ProjectDependenciesResolver</role>
-        </requirement>
-        <requirement>
-          <role>org.apache.maven.repository.RepositorySystem</role>
-        </requirement>
-        <requirement>
-          <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
-          <field-name>lifecycleMappings</field-name>
-        </requirement>
-        <requirement>
-          <role>org.apache.maven.plugin.version.PluginVersionResolver</role>
-        </requirement>
-        <requirement>
-          <role>org.apache.maven.plugin.prefix.PluginPrefixResolver</role>
-        </requirement>
-      </requirements>
-      <configuration>
-        <lifecycles>
-          <lifecycle>
-            <id>default</id>
-            <!-- START SNIPPET: lifecycle -->
-            <phases>
-              <phase>validate</phase>
-              <phase>initialize</phase>
-              <phase>generate-sources</phase>
-              <phase>process-sources</phase>
-              <phase>generate-resources</phase>
-              <phase>process-resources</phase>
-              <phase>compile</phase>
-              <phase>process-classes</phase>
-              <phase>generate-test-sources</phase>
-              <phase>process-test-sources</phase>
-              <phase>generate-test-resources</phase>
-              <phase>process-test-resources</phase>
-              <phase>test-compile</phase>
-              <phase>process-test-classes</phase>
-              <phase>test</phase>
-              <phase>prepare-package</phase>
-              <phase>package</phase>
-              <phase>pre-integration-test</phase>
-              <phase>integration-test</phase>
-              <phase>post-integration-test</phase>
-              <phase>verify</phase>
-              <phase>install</phase>
-              <phase>deploy</phase>
-            </phases>
-            <!-- END SNIPPET: lifecycle -->
-          </lifecycle>
-          <lifecycle>
-            <id>clean</id>
-            <phases>
-              <phase>pre-clean</phase>
-              <phase>clean</phase>
-              <phase>post-clean</phase>
-            </phases>
-            <default-phases>
-              <clean>org.apache.maven.plugins:maven-clean-plugin:clean
-              </clean>
-            </default-phases>
-          </lifecycle>
-          <lifecycle>
-            <id>site</id>
-            <phases>
-              <phase>pre-site</phase>
-              <phase>site</phase>
-              <phase>post-site</phase>
-              <phase>site-deploy</phase>
-            </phases>
-            <default-phases>
-              <site>org.apache.maven.plugins:maven-site-plugin:site
-              </site>
-              <site-deploy>org.apache.maven.plugins:maven-site-plugin:deploy
-              </site-deploy>
-            </default-phases>
-          </lifecycle>
-        </lifecycles>
-      </configuration>
-    </component>
+      <component>
+          <role>org.apache.maven.plugin.MavenPluginCollector</role>
+          <implementation>org.apache.maven.plugin.MavenPluginCollector
+          </implementation>
+      </component>
+      <component>
+          <role>org.apache.maven.lifecycle.LifecycleExecutor</role>
+          <implementation>org.apache.maven.lifecycle.DefaultLifecycleExecutor
+          </implementation>
+          <requirements>
+              <requirement>
+                  <role>org.apache.maven.lifecycle.LifeCyclePluginAnalyzer</role>
+              </requirement>
+              <requirement>
+                  <role>org.apache.maven.lifecycle.DefaultLifecycles</role>
+              </requirement>
+              <requirement>
+                  <role>org.codehaus.plexus.logging.Logger</role>
+                  <role-hint>default</role-hint>
+                  <field-name>logger</field-name>
+              </requirement>
+              <requirement>
+                  <role>org.apache.maven.lifecycle.internal.LifecycleModuleBuilder</role>
+              </requirement>
+              <requirement>
+                  <role>org.apache.maven.lifecycle.internal.LifecycleWeaveBuilder</role>
+              </requirement>
+              <requirement>
+                  <role>org.apache.maven.lifecycle.internal.BuildListCalculator</role>
+              </requirement>
+              <requirement>
+                  <role>org.apache.maven.lifecycle.internal.LifecycleDebugLogger</role>
+              </requirement>
+          </requirements>
+          
+      </component>
+      <component>
+        <role>org.apache.maven.lifecycle.DefaultLifecycles</role>
+        <implementation>org.apache.maven.lifecycle.DefaultLifecycles</implementation>
+
+        <configuration>
+          <lifecycles>
+            <lifecycle>
+              <id>default</id>
+              <!-- START SNIPPET: lifecycle -->
+              <phases>
+                <phase>validate</phase>
+                <phase>initialize</phase>
+                <phase>generate-sources</phase>
+                <phase>process-sources</phase>
+                <phase>generate-resources</phase>
+                <phase>process-resources</phase>
+                <phase>compile</phase>
+                <phase>process-classes</phase>
+                <phase>generate-test-sources</phase>
+                <phase>process-test-sources</phase>
+                <phase>generate-test-resources</phase>
+                <phase>process-test-resources</phase>
+                <phase>test-compile</phase>
+                <phase>process-test-classes</phase>
+                <phase>test</phase>
+                <phase>prepare-package</phase>
+                <phase>package</phase>
+                <phase>pre-integration-test</phase>
+                <phase>integration-test</phase>
+                <phase>post-integration-test</phase>
+                <phase>verify</phase>
+                <phase>install</phase>
+                <phase>deploy</phase>
+              </phases>
+              <!-- END SNIPPET: lifecycle -->
+            </lifecycle>
+            <lifecycle>
+              <id>clean</id>
+              <phases>
+                <phase>pre-clean</phase>
+                <phase>clean</phase>
+                <phase>post-clean</phase>
+              </phases>
+              <default-phases>
+                <clean>org.apache.maven.plugins:maven-clean-plugin:clean
+                </clean>
+              </default-phases>
+            </lifecycle>
+            <lifecycle>
+              <id>site</id>
+              <phases>
+                <phase>pre-site</phase>
+                <phase>site</phase>
+                <phase>post-site</phase>
+                <phase>site-deploy</phase>
+              </phases>
+              <default-phases>
+                <site>org.apache.maven.plugins:maven-site-plugin:site
+                </site>
+                <site-deploy>org.apache.maven.plugins:maven-site-plugin:deploy
+                </site-deploy>
+              </default-phases>
+            </lifecycle>
+          </lifecycles>
+          <schedules>
+              <scheduling>
+                   <lifecycle>default</lifecycle>
+                  <schedules>
+                      <schedule>
+                          <phase>compile</phase>
+                          <outputDependant>true</outputDependant>
+                          <mojoSynchronized>false</mojoSynchronized>
+                          <forkable>false</forkable>
+                      </schedule>
+                      <schedule>
+                          <phase>test-compile</phase>
+                          <outputDependant>true</outputDependant>
+                          <mojoSynchronized>false</mojoSynchronized>
+                          <forkable>false</forkable>
+                      </schedule>
+                      <schedule>
+                          <phase>test</phase>
+                          <outputDependant>false</outputDependant>
+                          <mojoSynchronized>false</mojoSynchronized>
+                          <forkable>true</forkable>
+                      </schedule>
+                      <schedule>
+                          <mojoClass>org.apache.maven.plugins:maven-assembly-plugin</mojoClass>
+                          <outputDependant>false</outputDependant>
+                          <mojoSynchronized>true</mojoSynchronized>
+                          <forkable>false</forkable>
+                      </schedule>
+                      <!-- schedule> Replaced by the modello stuff below
+                          <phase>generate-sources</phase>
+                          <outputDependant>true</outputDependant>
+                          <mojoSynchronized>true</mojoSynchronized>
+                          <forkable>false</forkable>
+                      </schedule -->
+                      <schedule>
+                          <mojoClass>org.codehaus.modello:modello-maven-plugin</mojoClass>
+                          <outputDependant>false</outputDependant>
+                          <mojoSynchronized>true</mojoSynchronized>
+                          <forkable>false</forkable>
+                      </schedule>
+                  </schedules>
+              </scheduling>
+          </schedules>
+        </configuration>
+      </component>
+      <component>
+        <role>org.apache.maven.lifecycle.LifeCyclePluginAnalyzer</role>
+        <implementation>org.apache.maven.lifecycle.internal.LifecyclePluginAnalyzerImpl</implementation>
+          <requirements>
+              <requirement>
+                <role>org.apache.maven.lifecycle.DefaultLifecycles</role>
+              </requirement>
+              <requirement>
+                <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
+                <field-name>lifecycleMappings</field-name>
+              </requirement>
+          </requirements>
+      </component>
 
     <component>
       <role>org.sonatype.plexus.components.sec.dispatcher.SecDispatcher
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/DefaultLifecyclesTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/DefaultLifecyclesTest.java
new file mode 100644
index 0000000..6838b5d
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/DefaultLifecyclesTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+
+package org.apache.maven.lifecycle;
+
+import org.codehaus.plexus.PlexusTestCase;
+import org.codehaus.plexus.component.annotations.Requirement;
+
+import java.util.List;
+
+/**
+ * @author Kristian Rosenvold
+ */
+
+public class DefaultLifecyclesTest
+        extends PlexusTestCase {
+    @Requirement
+    private DefaultLifecycles defaultLifeCycles;
+
+
+    protected void setUp()
+            throws Exception {
+        super.setUp();
+        defaultLifeCycles = lookup(DefaultLifecycles.class);
+    }
+
+    @Override
+    protected void tearDown()
+            throws Exception {
+        defaultLifeCycles = null;
+        super.tearDown();
+    }
+
+    public void testLifecycle() throws Exception {
+        final List<Lifecycle> cycles = defaultLifeCycles.getLifeCycles();
+        assertNotNull(cycles);
+        final Lifecycle lifecycle = cycles.get(0);
+        assertEquals("default", lifecycle.getId());
+        assertEquals(23, lifecycle.getPhases().size());
+
+    }
+
+    public void testScheduling() throws Exception {
+        final List<Scheduling> schedulings = defaultLifeCycles.getSchedules();
+        assertNotNull(schedulings);
+        assertTrue(schedulings.size() > 0);
+        Scheduling first = schedulings.get(0);
+        assertNotNull(first.getLifecycle());
+        final List<Schedule> schedules = first.getSchedules();
+        assertNotNull(schedules);
+        // Ok so if we ever change the first schedule this test will have to change
+        Schedule firstSchedule = schedules.get(0);
+        assertEquals("compile", firstSchedule.getPhase());
+        assertTrue("Should be blocking", firstSchedule.isOutputDependant());
+        assertFalse("Should not be forkable", firstSchedule.isForkable());
+    }
+
+}
\ No newline at end of file
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorSubModulesTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorSubModulesTest.java
new file mode 100644
index 0000000..a2a4317
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorSubModulesTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+
+package org.apache.maven.lifecycle;
+
+import org.apache.maven.AbstractCoreMavenComponentTestCase;
+import org.apache.maven.exception.ExceptionHandler;
+import org.apache.maven.lifecycle.internal.*;
+import org.codehaus.plexus.component.annotations.Requirement;
+
+/**
+ * Just asserts that it's able to create those components. Handy when plexus gets a nervous breakdown.
+ * @author Kristian Rosenvold
+ */
+
+public class LifecycleExecutorSubModulesTest extends AbstractCoreMavenComponentTestCase
+{
+    @Requirement
+    private DefaultLifecycles defaultLifeCycles;
+    @Requirement
+    private MojoExecutor mojoExecutor;
+    @Requirement
+    private LifecycleModuleBuilder lifeCycleBuilder;
+    @Requirement
+    private LifecycleDependencyResolver lifeCycleDependencyResolver;
+    @Requirement
+    private LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator;
+    @Requirement
+    private LifeCyclePluginAnalyzer lifeCyclePluginAnalyzer;
+    @Requirement
+    private LifecycleTaskSegmentCalculator lifeCycleTaskSegmentCalculator;
+
+    
+
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        defaultLifeCycles = lookup( DefaultLifecycles.class );
+        mojoExecutor = lookup( MojoExecutor.class);
+        lifeCycleBuilder = lookup( LifecycleModuleBuilder.class);
+        lifeCycleDependencyResolver = lookup( LifecycleDependencyResolver.class);
+        lifeCycleExecutionPlanCalculator = lookup( LifecycleExecutionPlanCalculator.class);
+        lifeCyclePluginAnalyzer = lookup( LifecyclePluginAnalyzerImpl.class);
+        lifeCycleTaskSegmentCalculator = lookup( LifecycleTaskSegmentCalculator.class);
+        lookup( ExceptionHandler.class );
+    }
+
+    @Override
+    protected void tearDown() throws Exception
+    {
+        defaultLifeCycles = null;
+        super.tearDown();
+    }
+
+    protected String getProjectsDirectory()
+    {
+        return "src/test/projects/lifecycle-executor";
+    }
+
+    public void testCrweation() throws Exception
+    {
+       assertNotNull(defaultLifeCycles);
+       assertNotNull(mojoExecutor);
+       assertNotNull(lifeCycleBuilder);
+       assertNotNull(lifeCycleDependencyResolver);
+       assertNotNull(lifeCycleExecutionPlanCalculator);
+       assertNotNull(lifeCyclePluginAnalyzer);
+       assertNotNull( lifeCycleTaskSegmentCalculator);
+    }
+
+}
\ No newline at end of file
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 e2dadd0..8c629b9 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
@@ -1,16 +1,36 @@
+/*
+ * 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.
+ */
+
+
 package org.apache.maven.lifecycle;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.maven.AbstractCoreMavenComponentTestCase;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.exception.ExceptionHandler;
 import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.internal.*;
 import org.apache.maven.model.Plugin;
-import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.*;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
 import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 
@@ -19,12 +39,23 @@ public class LifecycleExecutorTest
 {
     @Requirement
     private DefaultLifecycleExecutor lifecycleExecutor;
+
+    @Requirement
+    private LifecycleTaskSegmentCalculatorImpl lifeCycleTaskSegmentCalculator;
+    @Requirement
+    private LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator;
+    @Requirement
+    private MojoDescriptorCreator mojoDescriptorCreator;
+
     
     protected void setUp()
         throws Exception
     {
         super.setUp();
         lifecycleExecutor = (DefaultLifecycleExecutor) lookup( LifecycleExecutor.class );
+        lifeCycleTaskSegmentCalculator = (LifecycleTaskSegmentCalculatorImpl) lookup(LifecycleTaskSegmentCalculator.class);
+        lifeCycleExecutionPlanCalculator = lookup ( LifecycleExecutionPlanCalculator.class);
+        mojoDescriptorCreator = lookup (MojoDescriptorCreator.class);
         lookup( ExceptionHandler.class );
     }
 
@@ -44,7 +75,7 @@ public class LifecycleExecutorTest
     // -----------------------------------------------------------------------------------------------
     // Tests which exercise the lifecycle executor when it is dealing with default lifecycle phases.
     // -----------------------------------------------------------------------------------------------
-    
+
     public void testCalculationOfBuildPlanWithIndividualTaskWherePluginIsSpecifiedInThePom()
         throws Exception
     {
@@ -54,7 +85,7 @@ public class LifecycleExecutorTest
         MavenSession session = createMavenSession( pom );
         assertEquals( "project-basic", session.getCurrentProject().getArtifactId() );
         assertEquals( "1.0", session.getCurrentProject().getVersion() );
-        List<MojoExecution> executionPlan = lifecycleExecutor.calculateExecutionPlan( session, "resources:resources" ).getExecutions();
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan( session, "resources:resources" ));
         assertEquals( 1, executionPlan.size() );
         MojoExecution mojoExecution = executionPlan.get( 0 );
         assertNotNull( mojoExecution );
@@ -72,7 +103,7 @@ public class LifecycleExecutorTest
         MavenSession session = createMavenSession( pom );
         assertEquals( "project-basic", session.getCurrentProject().getArtifactId() );
         assertEquals( "1.0", session.getCurrentProject().getVersion() );
-        List<MojoExecution> executionPlan = lifecycleExecutor.calculateExecutionPlan( session, "clean" ).getExecutions();
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan( session, "clean" ));
         assertEquals( 1, executionPlan.size() );
         MojoExecution mojoExecution = executionPlan.get( 0 );
         assertNotNull( mojoExecution );
@@ -90,7 +121,7 @@ public class LifecycleExecutorTest
         MavenSession session = createMavenSession( pom );
         assertEquals( "project-basic", session.getCurrentProject().getArtifactId() );
         assertEquals( "1.0", session.getCurrentProject().getVersion() );
-        List<MojoExecution> executionPlan = lifecycleExecutor.calculateExecutionPlan( session, "clean:clean" ).getExecutions();
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan( session, "clean:clean" ));
         assertEquals( 1, executionPlan.size() );
         MojoExecution mojoExecution = executionPlan.get( 0 );
         assertNotNull( mojoExecution );
@@ -99,6 +130,14 @@ public class LifecycleExecutorTest
         assertEquals( "0.1", mojoExecution.getMojoDescriptor().getPluginDescriptor().getVersion() );
     }
 
+    List<MojoExecution> getExecutions(MavenExecutionPlan mavenExecutionPlan){
+        List<MojoExecution> result = new ArrayList<MojoExecution>();
+        for (ExecutionPlanItem executionPlanItem : mavenExecutionPlan) {
+            result.add( executionPlanItem.getMojoExecution());
+        }
+        return result;
+    }
+
     // We need to take in multiple lifecycles
     public void testCalculationOfBuildPlanTasksOfTheCleanLifecycleAndTheInstallLifecycle()
         throws Exception
@@ -107,7 +146,7 @@ public class LifecycleExecutorTest
         MavenSession session = createMavenSession( pom );
         assertEquals( "project-with-additional-lifecycle-elements", session.getCurrentProject().getArtifactId() );
         assertEquals( "1.0", session.getCurrentProject().getVersion() );
-        List<MojoExecution> executionPlan = lifecycleExecutor.calculateExecutionPlan( session, "clean", "install" ).getExecutions();        
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan( session, "clean", "install" ));
                         
         //[01] clean:clean
         //[02] resources:resources
@@ -143,13 +182,13 @@ public class LifecycleExecutorTest
         assertEquals( "project-with-multiple-executions", session.getCurrentProject().getArtifactId() );
         assertEquals( "1.0.1", session.getCurrentProject().getVersion() );
         
-        MavenExecutionPlan plan = lifecycleExecutor.calculateExecutionPlan( session, "clean", "install" );
+        MavenExecutionPlan plan = calculateExecutionPlan( session, "clean", "install" );
         
         assertTrue( plan.getRequiredResolutionScopes().contains( Artifact.SCOPE_COMPILE ) );
         assertTrue( plan.getRequiredResolutionScopes().contains( Artifact.SCOPE_RUNTIME ) );
         assertTrue( plan.getRequiredResolutionScopes().contains( Artifact.SCOPE_TEST ) );
         
-        List<MojoExecution> executions = plan.getExecutions();        
+        List<MojoExecution> executions = getExecutions(plan);        
         
         //[01] clean:clean
         //[02] modello:xpp3-writer
@@ -199,7 +238,7 @@ public class LifecycleExecutorTest
         MavenSession session = createMavenSession( pom );
         assertEquals( "project-with-additional-lifecycle-elements", session.getCurrentProject().getArtifactId() );
         assertEquals( "1.0", session.getCurrentProject().getVersion() );
-        List<MojoExecution> executionPlan = lifecycleExecutor.calculateExecutionPlan( session, "package" ).getExecutions();
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan( session, "package" ));
         
         //[01] resources:resources
         //[02] compiler:compile
@@ -236,18 +275,40 @@ public class LifecycleExecutorTest
         File pom = getProject( "project-with-additional-lifecycle-elements" );
         MavenSession session = createMavenSession( pom );
         MojoDescriptor mojoDescriptor =
-            lifecycleExecutor.getMojoDescriptor( "org.apache.maven.its.plugins:maven-it-plugin:0.1:java",
+            mojoDescriptorCreator.getMojoDescriptor( "org.apache.maven.its.plugins:maven-it-plugin:0.1:java",
                                                  session, session.getCurrentProject() );
-        Xpp3Dom dom = lifecycleExecutor.convert( mojoDescriptor );
+        Xpp3Dom dom = MojoDescriptorCreator.convert( mojoDescriptor );
         System.out.println( dom );
     }
 
+    // Todo: This method is kind of an oddity. It is only called from the LifecycleExecutorTest, hence it should
+    // really not exist, or at least be moved into the test class.
+
+    MavenExecutionPlan calculateExecutionPlan( MavenSession session, String... tasks )
+        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+            MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+        PluginManagerException, LifecyclePhaseNotFoundException, LifecycleNotFoundException,
+            PluginVersionResolutionException
+    {
+        List<org.apache.maven.lifecycle.internal.TaskSegment> taskSegments = lifeCycleTaskSegmentCalculator.calculateTaskSegments(session, Arrays.asList(tasks));
+
+        org.apache.maven.lifecycle.internal.TaskSegment mergedSegment = new org.apache.maven.lifecycle.internal.TaskSegment( false );
+
+        for ( org.apache.maven.lifecycle.internal.TaskSegment taskSegment : taskSegments )
+        {
+            mergedSegment.getTasks().addAll(taskSegment.getTasks());
+        }
+
+        return lifeCycleExecutionPlanCalculator.calculateExecutionPlan( session, session.getCurrentProject(), mergedSegment.getTasks());
+    }
+
+
     public void testPluginPrefixRetrieval()
         throws Exception
     {
         File pom = getProject( "project-basic" );
         MavenSession session = createMavenSession( pom );
-        Plugin plugin = lifecycleExecutor.findPluginForPrefix( "resources", session );
+        Plugin plugin = mojoDescriptorCreator.findPluginForPrefix( "resources", session );
         assertEquals( "org.apache.maven.plugins", plugin.getGroupId() );
         assertEquals( "maven-resources-plugin", plugin.getArtifactId() );
     }    
@@ -259,7 +320,7 @@ public class LifecycleExecutorTest
     {
         File pom = getProject( "project-basic" );
         MavenSession session = createMavenSession( pom );
-        Plugin plugin = lifecycleExecutor.findPluginForPrefix( "clean", session );
+        Plugin plugin = mojoDescriptorCreator.findPluginForPrefix( "clean", session );
         assertNotNull( plugin );
     }
     
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/MavenExecutionPlanTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/MavenExecutionPlanTest.java
new file mode 100644
index 0000000..801fb0a
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/MavenExecutionPlanTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+
+package org.apache.maven.lifecycle;
+
+import junit.framework.TestCase;
+import org.apache.maven.lifecycle.internal.ExecutionPlanItem;
+import org.apache.maven.lifecycle.internal.stub.DefaultLifecyclesStub;
+import org.apache.maven.lifecycle.internal.stub.LifecycleExecutionPlanCalculatorStub;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class MavenExecutionPlanTest extends TestCase {
+    public void testFindFirstWithMatchingSchedule() throws Exception {
+        MavenExecutionPlan plan = LifecycleExecutionPlanCalculatorStub.getProjectAExceutionPlan();
+        final List<Scheduling> cycles = DefaultLifecyclesStub.getSchedulingList();
+        final Schedule schedule = cycles.get(0).getSchedules().get(0);
+        final ExecutionPlanItem item1 = plan.findFirstWithMatchingSchedule(schedule);
+
+        final Iterator<ExecutionPlanItem> planItemIterator = plan.iterator();
+        planItemIterator.next();
+        planItemIterator.next();
+        assertEquals(planItemIterator.next(), item1);  // Todo, consider finding cleaner way to access second element of plan A ;)
+    }
+
+    public void testForceAllComplete() throws Exception {
+        MavenExecutionPlan plan = LifecycleExecutionPlanCalculatorStub.getProjectAExceutionPlan();
+        plan.forceAllComplete();
+        final Iterator<ExecutionPlanItem> planItemIterator = plan.iterator();
+        assertFalse(planItemIterator.next().ensureComplete());
+        assertFalse(planItemIterator.next().ensureComplete());
+    }
+
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/BuildListCalculatorTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/BuildListCalculatorTest.java
new file mode 100644
index 0000000..7979b2d
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/BuildListCalculatorTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import junit.framework.TestCase;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.internal.stub.LifecycleTaskSegmentCalculatorStub;
+import org.apache.maven.lifecycle.internal.stub.ProjectDependencyGraphStub;
+
+import java.util.List;
+
+public class BuildListCalculatorTest extends TestCase {
+
+    public void testCalculateProjectBuilds() throws Exception {
+        BuildListCalculator buildListCalculator = createBuildListCalculator();
+        final MavenSession session = ProjectDependencyGraphStub.getMavenSession();
+        final ProjectBuildList buildList = buildListCalculator.calculateProjectBuilds(session);
+        final List<ProjectBuildList> segments = buildList.getByTaskSegments();
+        assertEquals("Stub data contains 3 segments", 3, segments.size());
+        final ProjectBuildList first = segments.get(0);
+        final ProjectBuild build = first.get(0);
+        assertNotNull( build);
+    }
+
+    public static BuildListCalculator createBuildListCalculator(){
+        LifecycleTaskSegmentCalculator lifecycleTaskSegmentCalculator = new LifecycleTaskSegmentCalculatorStub();
+        return new BuildListCalculator(lifecycleTaskSegmentCalculator);
+    }
+
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/BuilderCommonTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/BuilderCommonTest.java
new file mode 100644
index 0000000..1e20a7f
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/BuilderCommonTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import junit.framework.TestCase;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.lifecycle.internal.stub.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class BuilderCommonTest extends TestCase {
+    public void testResolveBuildPlan() throws Exception {
+        MavenSession original = ProjectDependencyGraphStub.getMavenSession();
+
+        final TaskSegment taskSegment1 = new TaskSegment(false);
+        final MavenSession session1 = original.clone();
+        session1.setCurrentProject(ProjectDependencyGraphStub.A);
+
+        final BuilderCommon builderCommon = getBuilderCommon();
+        final MavenExecutionPlan plan = builderCommon.resolveBuildPlan(session1, ProjectDependencyGraphStub.A, taskSegment1);
+        assertEquals(LifecycleExecutionPlanCalculatorStub.getProjectAExceutionPlan().size(), plan.size());
+
+    }
+
+
+    public void testHandleBuildError() throws Exception {
+    }
+
+    public void testAttachToThread() throws Exception {
+    }
+
+    public void testGetKey() throws Exception {
+    }
+
+    public static BuilderCommon getBuilderCommon() {
+        final LifecycleDebugLogger logger = new LifecycleDebugLogger(new LoggerStub());
+        final LifecycleDependencyResolver lifecycleDependencyResolver =
+                new LifecycleDependencyResolver(new ProjectDependenciesResolverStub(), new LoggerStub());
+        return new BuilderCommon(logger, new LifecycleExecutionPlanCalculatorStub(), lifecycleDependencyResolver);
+    }
+
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ExecutionPlanItemTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ExecutionPlanItemTest.java
new file mode 100644
index 0000000..dd65bea
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ExecutionPlanItemTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import junit.framework.TestCase;
+import org.apache.maven.lifecycle.Schedule;
+import org.apache.maven.lifecycle.internal.stub.MojoExecutorStub;
+import org.apache.maven.plugin.MojoExecution;
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class ExecutionPlanItemTest extends TestCase {
+
+    public void testSetComplete() throws Exception {
+        ExecutionPlanItem item = createExecutionPlanItem("testMojo", null);
+        item.setComplete();  // This itself is a valid test
+        assertFalse( item.ensureComplete());
+    }
+
+    public void testWaitUntilDone() throws Exception {
+
+        final ExecutionPlanItem item = createExecutionPlanItem("testMojo", createExecutionPlanItem("testMojo2", null));
+        new Thread(new Runnable(){
+            public void run() {
+                item.setComplete();
+            }
+        }).start();
+        item.waitUntilDone();
+    }
+
+
+    public static ExecutionPlanItem createExecutionPlanItem(String mojoDescription, ExecutionPlanItem downStream) {
+        return createExecutionPlanItem( mojoDescription, downStream, null);
+    }
+    public static ExecutionPlanItem createExecutionPlanItem(String mojoDescription, ExecutionPlanItem downStream, Schedule schedule) {
+        return new ExecutionPlanItem(new MojoExecution(MojoExecutorStub.createMojoDescriptor(mojoDescription)), schedule);
+    }
+
+
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculatorTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculatorTest.java
new file mode 100644
index 0000000..b425367
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculatorTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import junit.framework.TestCase;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.lifecycle.internal.stub.*;
+
+/**
+ * @author Kristian Rosenvold>
+ */
+
+public class LifecycleExecutionPlanCalculatorTest extends TestCase {
+
+    public void testCalculateExecutionPlanWithGoalTasks() throws Exception {
+        MojoDescriptorCreator mojoDescriptorCreator = createMojoDescriptorCreator();
+        LifecycleExecutionPlanCalculator lifecycleExecutionPlanCalculator = createExecutionPlaceCalculator(mojoDescriptorCreator);
+
+        final GoalTask goalTask1 = new GoalTask(LifecycleExecutionPlanCalculatorStub.createMojoDescriptor("compile"));
+        final GoalTask goalTask2 = new GoalTask(LifecycleExecutionPlanCalculatorStub.createMojoDescriptor("test"));
+        final TaskSegment taskSegment1 = new TaskSegment(false, goalTask1, goalTask2);
+        final MavenSession session1 = ProjectDependencyGraphStub.getMavenSession(ProjectDependencyGraphStub.A);
+
+        MavenExecutionPlan executionPlan = lifecycleExecutionPlanCalculator.calculateExecutionPlan(session1, ProjectDependencyGraphStub.A, taskSegment1.getTasks());
+        assertEquals(2, executionPlan.size());
+
+        final GoalTask goalTask3 = new GoalTask(LifecycleExecutionPlanCalculatorStub.createMojoDescriptor("test"));
+        final TaskSegment taskSegment2 = new TaskSegment(false, goalTask1, goalTask2, goalTask3);
+        MavenExecutionPlan executionPlan2 = lifecycleExecutionPlanCalculator.calculateExecutionPlan(session1, ProjectDependencyGraphStub.A, taskSegment2.getTasks());
+        assertEquals(3, executionPlan2.size());
+    }
+
+    // Maybe also make one with LifeCycleTasks
+
+    private LifecycleExecutionPlanCalculator createExecutionPlaceCalculator(MojoDescriptorCreator mojoDescriptorCreator) {
+        return new LifecycleExecutionPlanCalculatorImpl(
+            new PluginVersionResolverStub(),
+            new BuildPluginManagerStub(),
+            DefaultLifecyclesStub.createDefaultLifeCycles(),
+            mojoDescriptorCreator);
+    }
+
+    private MojoDescriptorCreator createMojoDescriptorCreator() {
+        return new MojoDescriptorCreator(new PluginVersionResolverStub(),
+                new BuildPluginManagerStub(), new PluginPrefixResolverStub());
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculatorTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculatorTest.java
new file mode 100644
index 0000000..b8d760a
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculatorTest.java
@@ -0,0 +1,321 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import org.apache.maven.AbstractCoreMavenComponentTestCase;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.exception.ExceptionHandler;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.LifecycleNotFoundException;
+import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.lifecycle.MojoExecutionXPathContainer;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Kristian Rosenvold
+ */
+
+public class LifecycleTaskSegmentCalculatorTest
+    extends AbstractCoreMavenComponentTestCase
+{
+
+    @Requirement
+    private LifecycleTaskSegmentCalculatorImpl lifeCycleTaskSegmentCalculator;
+    @Requirement
+    private LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator;
+    @Requirement
+    private MojoDescriptorCreator mojoDescriptorCreator;
+
+
+
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+        lifeCycleTaskSegmentCalculator = (LifecycleTaskSegmentCalculatorImpl) lookup(LifecycleTaskSegmentCalculator.class);
+        lifeCycleExecutionPlanCalculator = lookup ( LifecycleExecutionPlanCalculator.class);
+        mojoDescriptorCreator = lookup (MojoDescriptorCreator.class);
+        lookup( ExceptionHandler.class );
+    }
+
+    @Override
+    protected void tearDown()
+        throws Exception
+    {
+        super.tearDown();
+    }
+
+    protected String getProjectsDirectory()
+    {
+        return "src/test/projects/lifecycle-executor";
+    }
+
+    // -----------------------------------------------------------------------------------------------
+    // Tests which exercise the lifecycle executor when it is dealing with default lifecycle phases.
+    // -----------------------------------------------------------------------------------------------
+
+    public void testCalculationOfBuildPlanWithIndividualTaskWherePluginIsSpecifiedInThePom()
+        throws Exception
+    {
+        // We are doing something like "mvn resources:resources" where no version is specified but this
+        // project we are working on has the version specified in the POM so the version should come from there.
+        File pom = getProject( "project-basic" );
+        MavenSession session = createMavenSession( pom );
+        assertEquals( "project-basic", session.getCurrentProject().getArtifactId() );
+        assertEquals( "1.0", session.getCurrentProject().getVersion() );
+        List<MojoExecution> executionPlan = getExecutions( calculateExecutionPlan( session, "resources:resources" ));
+        assertEquals( 1, executionPlan.size() );
+        MojoExecution mojoExecution = executionPlan.get( 0 );
+        assertNotNull( mojoExecution );
+        assertEquals( "org.apache.maven.plugins", mojoExecution.getMojoDescriptor().getPluginDescriptor().getGroupId() );
+        assertEquals( "maven-resources-plugin", mojoExecution.getMojoDescriptor().getPluginDescriptor().getArtifactId() );
+        assertEquals( "0.1", mojoExecution.getMojoDescriptor().getPluginDescriptor().getVersion() );
+    }
+
+    public void testCalculationOfBuildPlanWithIndividualTaskOfTheCleanLifecycle()
+        throws Exception
+    {
+        // We are doing something like "mvn clean:clean" where no version is specified but this
+        // project we are working on has the version specified in the POM so the version should come from there.
+        File pom = getProject( "project-basic" );
+        MavenSession session = createMavenSession( pom );
+        assertEquals( "project-basic", session.getCurrentProject().getArtifactId() );
+        assertEquals( "1.0", session.getCurrentProject().getVersion() );
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan( session, "clean" ));
+        assertEquals( 1, executionPlan.size() );
+        MojoExecution mojoExecution = executionPlan.get( 0 );
+        assertNotNull( mojoExecution );
+        assertEquals( "org.apache.maven.plugins", mojoExecution.getMojoDescriptor().getPluginDescriptor().getGroupId() );
+        assertEquals( "maven-clean-plugin", mojoExecution.getMojoDescriptor().getPluginDescriptor().getArtifactId() );
+        assertEquals( "0.1", mojoExecution.getMojoDescriptor().getPluginDescriptor().getVersion() );
+    }
+
+    public void testCalculationOfBuildPlanWithIndividualTaskOfTheCleanCleanGoal()
+        throws Exception
+    {
+        // We are doing something like "mvn clean:clean" where no version is specified but this
+        // project we are working on has the version specified in the POM so the version should come from there.
+        File pom = getProject( "project-basic" );
+        MavenSession session = createMavenSession( pom );
+        assertEquals( "project-basic", session.getCurrentProject().getArtifactId() );
+        assertEquals( "1.0", session.getCurrentProject().getVersion() );
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan( session, "clean:clean" ));
+        assertEquals( 1, executionPlan.size() );
+        MojoExecution mojoExecution = executionPlan.get( 0 );
+        assertNotNull( mojoExecution );
+        assertEquals( "org.apache.maven.plugins", mojoExecution.getMojoDescriptor().getPluginDescriptor().getGroupId() );
+        assertEquals( "maven-clean-plugin", mojoExecution.getMojoDescriptor().getPluginDescriptor().getArtifactId() );
+        assertEquals( "0.1", mojoExecution.getMojoDescriptor().getPluginDescriptor().getVersion() );
+    }
+
+    // We need to take in multiple lifecycles
+    public void testCalculationOfBuildPlanTasksOfTheCleanLifecycleAndTheInstallLifecycle()
+        throws Exception
+    {
+        File pom = getProject( "project-with-additional-lifecycle-elements" );
+        MavenSession session = createMavenSession( pom );
+        assertEquals( "project-with-additional-lifecycle-elements", session.getCurrentProject().getArtifactId() );
+        assertEquals( "1.0", session.getCurrentProject().getVersion() );
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan( session, "clean", "install" ));
+
+        //[01] clean:clean
+        //[02] resources:resources
+        //[03] compiler:compile
+        //[04] it:generate-metadata
+        //[05] resources:testResources
+        //[06] compiler:testCompile
+        //[07] it:generate-test-metadata
+        //[08] surefire:test
+        //[09] jar:jar
+        //[10] install:install
+        //
+        assertEquals( 10, executionPlan.size() );
+
+        assertEquals( "clean:clean", executionPlan.get( 0 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "resources:resources", executionPlan.get( 1 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "compiler:compile", executionPlan.get( 2 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "it:generate-metadata", executionPlan.get( 3 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "resources:testResources", executionPlan.get( 4 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "compiler:testCompile", executionPlan.get( 5 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "it:generate-test-metadata", executionPlan.get( 6 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "surefire:test", executionPlan.get( 7 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "jar:jar", executionPlan.get( 8 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "install:install", executionPlan.get( 9 ).getMojoDescriptor().getFullGoalName() );
+    }
+
+    // We need to take in multiple lifecycles
+    public void testCalculationOfBuildPlanWithMultipleExecutionsOfModello()
+        throws Exception
+    {
+        File pom = getProject( "project-with-multiple-executions" );
+        MavenSession session = createMavenSession( pom );
+        assertEquals( "project-with-multiple-executions", session.getCurrentProject().getArtifactId() );
+        assertEquals( "1.0.1", session.getCurrentProject().getVersion() );
+
+        MavenExecutionPlan plan = calculateExecutionPlan( session, "clean", "install" );
+
+        assertTrue( plan.getRequiredResolutionScopes().contains( Artifact.SCOPE_COMPILE ) );
+        assertTrue( plan.getRequiredResolutionScopes().contains( Artifact.SCOPE_RUNTIME ) );
+        assertTrue( plan.getRequiredResolutionScopes().contains( Artifact.SCOPE_TEST ) );
+
+        List<MojoExecution> executions = getExecutions(plan);
+
+        //[01] clean:clean
+        //[02] modello:xpp3-writer
+        //[03] modello:java
+        //[04] modello:xpp3-reader
+        //[05] modello:xpp3-writer
+        //[06] modello:java
+        //[07] modello:xpp3-reader
+        //[08] plugin:descriptor
+        //[09] resources:resources
+        //[10] compiler:compile
+        //[11] resources:testResources
+        //[12] compiler:testCompile
+        //[13] surefire:test
+        //[14] jar:jar
+        //[15] plugin:addPluginArtifactMetadata
+        //[16] install:install
+        //
+
+        assertEquals( 16, executions.size() );
+
+        assertEquals( "clean:clean", executions.get( 0 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "it:xpp3-writer", executions.get( 1 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "it:java", executions.get( 2 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "it:xpp3-reader", executions.get( 3 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "it:xpp3-writer", executions.get( 4 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "it:java", executions.get( 5 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "it:xpp3-reader", executions.get( 6 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "plugin:descriptor", executions.get( 7 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "resources:resources", executions.get( 8 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "compiler:compile", executions.get( 9 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "resources:testResources", executions.get( 10 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "compiler:testCompile", executions.get( 11 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "surefire:test", executions.get( 12 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "jar:jar", executions.get( 13 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "plugin:addPluginArtifactMetadata", executions.get( 14 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "install:install", executions.get( 15 ).getMojoDescriptor().getFullGoalName() );
+
+        assertEquals( "src/main/mdo/remote-resources.mdo", new MojoExecutionXPathContainer( executions.get( 1 ) ).getValue( "configuration/models[1]/model" ) );
+        assertEquals( "src/main/mdo/supplemental-model.mdo", new MojoExecutionXPathContainer( executions.get( 4 ) ).getValue( "configuration/models[1]/model" ) );
+    }
+
+    public void testLifecycleQueryingUsingADefaultLifecyclePhase()
+        throws Exception
+    {
+        File pom = getProject( "project-with-additional-lifecycle-elements" );
+        MavenSession session = createMavenSession( pom );
+        assertEquals( "project-with-additional-lifecycle-elements", session.getCurrentProject().getArtifactId() );
+        assertEquals( "1.0", session.getCurrentProject().getVersion() );
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan( session, "package" ));
+
+        //[01] resources:resources
+        //[02] compiler:compile
+        //[03] it:generate-metadata
+        //[04] resources:testResources
+        //[05] compiler:testCompile
+        //[06] plexus-component-metadata:generate-test-metadata
+        //[07] surefire:test
+        //[08] jar:jar
+        //
+        assertEquals( 8, executionPlan.size() );
+
+        assertEquals( "resources:resources", executionPlan.get( 0 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "compiler:compile", executionPlan.get( 1 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "it:generate-metadata", executionPlan.get( 2 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "resources:testResources", executionPlan.get( 3 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "compiler:testCompile", executionPlan.get( 4 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "it:generate-test-metadata", executionPlan.get( 5 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "surefire:test", executionPlan.get( 6 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals( "jar:jar", executionPlan.get( 7 ).getMojoDescriptor().getFullGoalName() );
+    }
+
+
+    public void testPluginConfigurationCreation()
+        throws Exception
+    {
+        File pom = getProject( "project-with-additional-lifecycle-elements" );
+        MavenSession session = createMavenSession( pom );
+        MojoDescriptor mojoDescriptor =
+            mojoDescriptorCreator.getMojoDescriptor( "org.apache.maven.its.plugins:maven-it-plugin:0.1:java",
+                                                 session, session.getCurrentProject() );
+        Xpp3Dom dom = MojoDescriptorCreator.convert( mojoDescriptor );
+        System.out.println( dom );
+    }
+
+
+    List<MojoExecution> getExecutions(MavenExecutionPlan mavenExecutionPlan){
+        List<MojoExecution> result = new ArrayList<MojoExecution>();
+        for (ExecutionPlanItem executionPlanItem : mavenExecutionPlan) {
+            result.add( executionPlanItem.getMojoExecution());
+        }
+        return result;
+    }
+
+    MavenExecutionPlan calculateExecutionPlan( MavenSession session, String... tasks )
+        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+            MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+        PluginManagerException, LifecyclePhaseNotFoundException, LifecycleNotFoundException,
+            PluginVersionResolutionException
+    {
+        List<TaskSegment> taskSegments = lifeCycleTaskSegmentCalculator.calculateTaskSegments(session, Arrays.asList(tasks));
+
+        TaskSegment mergedSegment = new TaskSegment( false );
+
+        for ( TaskSegment taskSegment : taskSegments )
+        {
+            mergedSegment.getTasks().addAll(taskSegment.getTasks());
+        }
+
+        return lifeCycleExecutionPlanCalculator.calculateExecutionPlan( session, session.getCurrentProject(), mergedSegment.getTasks());
+    }
+
+
+    public void testPluginPrefixRetrieval()
+        throws Exception
+    {
+        File pom = getProject( "project-basic" );
+        MavenSession session = createMavenSession( pom );
+        Plugin plugin = mojoDescriptorCreator.findPluginForPrefix( "resources", session );
+        assertEquals( "org.apache.maven.plugins", plugin.getGroupId() );
+        assertEquals( "maven-resources-plugin", plugin.getArtifactId() );
+    }
+
+    // Prefixes
+
+    public void testFindingPluginPrefixforCleanClean()
+        throws Exception
+    {
+        File pom = getProject( "project-basic" );
+        MavenSession session = createMavenSession( pom );
+        Plugin plugin = mojoDescriptorCreator.findPluginForPrefix( "clean", session );
+        assertNotNull( plugin );
+    }
+
+}
\ No newline at end of file
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilderTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilderTest.java
new file mode 100644
index 0000000..070c9d8
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilderTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import junit.framework.TestCase;
+import org.apache.maven.execution.DefaultMavenExecutionResult;
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.LifecycleNotFoundException;
+import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
+import org.apache.maven.lifecycle.internal.stub.*;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+
+import java.util.concurrent.*;
+
+/**
+ * @author Kristian Rosenvold>
+ */
+public class LifecycleWeaveBuilderTest extends TestCase {
+
+    public void testBuildProjectSynchronously() throws Exception {
+        final CompletionService<ProjectBuild> service = new CompletionServiceStub(true);
+        final ProjectBuildList projectBuildList = runWithCompletionService(service, false);
+        assertEquals("Expect all tasks to be scheduled", projectBuildList.size(), ((CompletionServiceStub) service).size());
+    }
+
+    public void testBuildProjectThreaded() throws Exception {
+        ExecutorService executor = Executors.newFixedThreadPool(10);
+        ExecutorCompletionService<ProjectBuild> service = new ExecutorCompletionService<ProjectBuild>(executor);
+        runWithCompletionService(service, false);
+        executor.shutdown();
+    }
+
+    public void testBuildProjectThreadedAggressive() throws Exception {
+        ExecutorService executor = Executors.newFixedThreadPool(10);
+        ExecutorCompletionService<ProjectBuild> service = new ExecutorCompletionService<ProjectBuild>(executor);
+        runWithCompletionService(service, true);
+        executor.shutdown();
+    }
+
+    private ProjectBuildList runWithCompletionService(CompletionService<ProjectBuild> service, boolean canScheduleAggressively) throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException, PluginVersionResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException, ExecutionException, InterruptedException {
+        final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        try {
+            BuildListCalculator buildListCalculator = BuildListCalculatorTest.createBuildListCalculator();
+            final MavenSession session = ProjectDependencyGraphStub.getMavenSession();
+            ProjectBuildList projectBuildList = buildListCalculator.calculateProjectBuilds(session);
+
+            final MojoExecutorStub mojoExecutorStub = new MojoExecutorStub();
+            final LifecycleWeaveBuilder builder = getWeaveBuilder(mojoExecutorStub);
+            final BuildContext buildContext = createBuildContext(session);
+            builder.buildProject(projectBuildList, buildContext, session, service, canScheduleAggressively);
+            
+           LifecycleExecutionPlanCalculatorStub lifecycleExecutionPlanCalculatorStub = new LifecycleExecutionPlanCalculatorStub();
+            final int expected = lifecycleExecutionPlanCalculatorStub.getNumberOfExceutions(projectBuildList);
+            assertEquals("All executions should be scheduled", expected, mojoExecutorStub.executions.size());
+            return projectBuildList;
+        } finally {
+            Thread.currentThread().setContextClassLoader(loader);
+        }
+    }
+
+
+    private BuildContext createBuildContext(MavenSession session) {
+        MavenExecutionResult mavenExecutionResult = new DefaultMavenExecutionResult();
+        return new BuildContext(mavenExecutionResult, null, null);
+    }
+
+    private LifecycleWeaveBuilder getWeaveBuilder(MojoExecutor mojoExecutor) {
+        final BuilderCommon builderCommon = getBuilderCommon();
+        return new LifecycleWeaveBuilder(mojoExecutor, builderCommon);
+
+    }
+
+    private BuilderCommon getBuilderCommon() {
+        final LifecycleDebugLogger logger = new LifecycleDebugLogger(new LoggerStub());
+        final LifecycleDependencyResolver lifecycleDependencyResolver =
+                new LifecycleDependencyResolver(new ProjectDependenciesResolverStub(), new LoggerStub());
+        return new BuilderCommon(logger, new LifecycleExecutionPlanCalculatorStub(), lifecycleDependencyResolver);
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ProjectBuildListTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ProjectBuildListTest.java
new file mode 100644
index 0000000..ab54ad2
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ProjectBuildListTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import junit.framework.TestCase;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.LifecycleNotFoundException;
+import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
+import org.apache.maven.lifecycle.internal.stub.ProjectDependencyGraphStub;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class ProjectBuildListTest extends TestCase {
+    
+    public void testGetByTaskSegments() throws Exception {
+        final MavenSession session = ProjectDependencyGraphStub.getMavenSession();
+        ProjectBuildList projectBuildList = ProjectDependencyGraphStub.getProjectBuildList(session);
+        assertTrue("This test assumes there are at least 6 elements in projectBuilds",  projectBuildList.size() >= 6 );
+
+        final List<ProjectBuildList> byTaskSegments = projectBuildList.getByTaskSegments();
+        assertEquals( 3, byTaskSegments.size());
+        final ProjectBuildList seg1 = byTaskSegments.get(0);
+        assertEquals(3, seg1.size());
+        Iterator<ProjectBuild> iter = seg1.iterator();
+        for (int i = 0; i < seg1.size(); i++){
+            assertEquals( projectBuildList.get(i), iter.next());
+        }
+        final ProjectBuildList seg2 = byTaskSegments.get(1);
+        assertEquals(2, seg2.size());
+        final ProjectBuildList seg3 = byTaskSegments.get(2);
+        assertEquals(1, seg3.size());
+    }
+
+    public void testgetByMavenprojectId() throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException, NoPluginFoundForPrefixException, PluginNotFoundException, MojoNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
+        final MavenSession originalSession = ProjectDependencyGraphStub.getMavenSession();
+        ProjectBuildList projectBuildList = ProjectDependencyGraphStub.getProjectBuildList(originalSession);
+        assertNotNull( projectBuildList.getProjectBuild( ProjectDependencyGraphStub.A ));
+        assertNull( projectBuildList.getProjectBuild( ProjectDependencyGraphStub.UNKNOWN ));
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ThreadOutputMuxerTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ThreadOutputMuxerTest.java
new file mode 100644
index 0000000..c258850
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ThreadOutputMuxerTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal;
+
+import junit.framework.TestCase;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.LifecycleNotFoundException;
+import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
+import org.apache.maven.lifecycle.internal.stub.ProjectDependencyGraphStub;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class ThreadOutputMuxerTest extends TestCase {
+
+    final String paid = "Paid";
+    final String in = "In";
+    final String full = "Full";
+
+    public void testSingleThreaded() throws Exception {
+        ProjectBuildList src = getProjectBuildList();
+        ProjectBuildList projectBuildList = new ProjectBuildList( Arrays.asList(src.get(0),src.get(1), src.get(2)));
+
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        PrintStream systemOut = new PrintStream(byteArrayOutputStream);
+        ThreadOutputMuxer threadOutputMuxer = new ThreadOutputMuxer(projectBuildList, systemOut);
+
+        threadOutputMuxer.associateThreadWithProjectBuild( projectBuildList.get(0));
+        System.out.print(paid);
+        assertEquals(paid.length(),  byteArrayOutputStream.size());
+        threadOutputMuxer.associateThreadWithProjectBuild( projectBuildList.get(1));
+        System.out.print(in);
+        assertEquals(paid.length(),  byteArrayOutputStream.size());
+        threadOutputMuxer.associateThreadWithProjectBuild( projectBuildList.get(2));
+        System.out.print(full);
+        assertEquals(paid.length(),  byteArrayOutputStream.size());
+
+        threadOutputMuxer.setThisModuleComplete( projectBuildList.get(0));
+        threadOutputMuxer.setThisModuleComplete( projectBuildList.get(1));
+        threadOutputMuxer.setThisModuleComplete( projectBuildList.get(2));
+        threadOutputMuxer.close();
+        assertEquals((paid + in + full).length() , byteArrayOutputStream.size());
+    }
+
+    public void testMultiThreaded() throws Exception {
+        ProjectBuildList projectBuildList = getProjectBuildList();
+
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        PrintStream systemOut = new PrintStream(byteArrayOutputStream);
+        final ThreadOutputMuxer threadOutputMuxer = new ThreadOutputMuxer(projectBuildList, systemOut);
+
+
+        final List<String> stringList = Arrays.asList("Thinkin", "of", "a","master", "plan",
+                "Cuz", "ain’t", "nuthin", "but", "sweat", "inside", "my", "hand"); 
+        Iterator<String> lyrics = stringList.iterator();
+        List<Outputter> outputters = new ArrayList<Outputter>();
+
+        ExecutorService executor = Executors.newFixedThreadPool(10);
+        CompletionService<ProjectBuild> service = new ExecutorCompletionService<ProjectBuild>(executor);
+
+        List<Future<ProjectBuild>> futures = new ArrayList<Future<ProjectBuild>>();
+        for (ProjectBuild projectBuild : projectBuildList) {
+            final Future<ProjectBuild> buildFuture = service.submit(new Outputter(threadOutputMuxer, projectBuild, lyrics.next()));
+            futures.add ( buildFuture);
+        }
+
+        for (Future<ProjectBuild> future : futures) {
+            future.get();
+        }
+        int expectedLength = 0; 
+        for (int i = 0; i < projectBuildList.size(); i++){
+            expectedLength += stringList.get(i).length();
+        }
+
+        threadOutputMuxer.close();
+        final byte[] bytes = byteArrayOutputStream.toByteArray();
+        String result = new String(bytes);
+        System.out.println(result);
+        assertEquals(result, expectedLength,  bytes.length );
+
+        
+    }
+
+    class Outputter implements Callable<ProjectBuild> {
+        private final ThreadOutputMuxer threadOutputMuxer;
+        private final ProjectBuild item;
+        private final String response;
+
+        Outputter(ThreadOutputMuxer threadOutputMuxer, ProjectBuild item, String response) {
+            this.threadOutputMuxer = threadOutputMuxer;
+            this.item = item;
+            this.response = response;
+        }
+
+        public ProjectBuild call() throws Exception {
+            threadOutputMuxer.associateThreadWithProjectBuild( item);
+            System.out.print(response);
+            threadOutputMuxer.setThisModuleComplete( item);
+            return item;
+        }
+    }
+
+
+
+    private ProjectBuildList getProjectBuildList() throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException, NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
+        final MavenSession session = ProjectDependencyGraphStub.getMavenSession();
+        return ProjectDependencyGraphStub.getProjectBuildList(session);
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/AboutTheStubs.html b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/AboutTheStubs.html
new file mode 100644
index 0000000..0149f97
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/AboutTheStubs.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+    <title>About these stubs</title>
+</head>
+<body>
+<h2>Design</h2>
+These stubs form an internally consistent data-set that is not expected to change. They are
+used to test the individual components in the lifecycle with data that has expected characteristics
+and can be asserted as desired.
+
+You can change/extend these stubs, and tests should not be breaking too much, since most tests
+assert using expected values from the stubs. Normally, when you try to use data from the stubs that
+have not been properly populated, you'll get a nullpointer in your test and you then have to
+identigy which stub creates that specific piece of data.
+                                            
+The most important stubs are:
+LifecycleExecutionPlanCalculatorStub
+ProjectDependencyGraphStub
+
+Since they define the primary structure of the project/build.
+
+The stubs define three top-level targets that are defined in  LifecycleTaskSegmentCalculatorStub;
+clean, aggr and install. "aggr" is an aggregating task while clean and install are lifecyclephases.
+There will be three items in the task list for this dataset.
+
+The stubs also exist at different "levels", where one test might wire stubs into a specific live implementation.
+In the next test that same "live implementation" will be used in a stub version instead.
+
+Not all live services have stubs, but can be added as needed.
+</body>
+</html>
\ No newline at end of file
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/BuildPluginManagerStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/BuildPluginManagerStub.java
new file mode 100644
index 0000000..b1e8157
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/BuildPluginManagerStub.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal.stub;
+
+import org.apache.maven.artifact.repository.RepositoryRequest;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class BuildPluginManagerStub implements BuildPluginManager {
+
+    public PluginDescriptor loadPlugin(Plugin plugin, RepositoryRequest repositoryRequest) throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException {
+        return null;
+    }
+
+    public MojoDescriptor getMojoDescriptor(Plugin plugin, String goal, RepositoryRequest repositoryRequest) throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException {
+        return null;
+    }
+
+    public ClassRealm getPluginRealm(MavenSession session, PluginDescriptor pluginDescriptor) throws PluginResolutionException, PluginManagerException {
+        return null;
+    }
+
+    public void executeMojo(MavenSession session, MojoExecution execution) throws MojoFailureException, MojoExecutionException, PluginConfigurationException, PluginManagerException {
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/CompletionServiceStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/CompletionServiceStub.java
new file mode 100644
index 0000000..0dd1ad8
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/CompletionServiceStub.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal.stub;
+
+import org.apache.maven.lifecycle.internal.ProjectBuild;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class CompletionServiceStub implements CompletionService<ProjectBuild> {
+    List<FutureTask<ProjectBuild>> projectBuildFutureTasks =   Collections.synchronizedList( new ArrayList<FutureTask<ProjectBuild>>());
+    final boolean finishImmediately;
+
+
+    public int size() {
+        return projectBuildFutureTasks.size();
+    }
+
+    public CompletionServiceStub(boolean finishImmediately) {
+        this.finishImmediately = finishImmediately;
+    }
+
+    public Future<ProjectBuild> submit(Callable<ProjectBuild> task) {
+        FutureTask<ProjectBuild> projectBuildFutureTask = new FutureTask<ProjectBuild>(task);
+        projectBuildFutureTasks.add( projectBuildFutureTask);
+        if (finishImmediately) projectBuildFutureTask.run();
+        return projectBuildFutureTask; 
+    }
+
+    public Future<ProjectBuild> submit(Runnable task, ProjectBuild result) {
+        FutureTask<ProjectBuild> projectBuildFutureTask = new FutureTask<ProjectBuild>(task, result);
+        projectBuildFutureTasks.add( projectBuildFutureTask);
+        if (finishImmediately) projectBuildFutureTask.run();
+        return projectBuildFutureTask;
+    }
+
+    public Future<ProjectBuild> take() throws InterruptedException {
+        return null;
+    }
+
+    public Future<ProjectBuild> poll() {
+        return null;
+    }
+
+    public Future<ProjectBuild> poll(long timeout, TimeUnit unit) throws InterruptedException {
+        return null;  
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/DefaultLifecyclesStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/DefaultLifecyclesStub.java
new file mode 100644
index 0000000..147c41e
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/DefaultLifecyclesStub.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal.stub;
+
+import org.apache.maven.lifecycle.DefaultLifecycles;
+import org.apache.maven.lifecycle.Lifecycle;
+import org.apache.maven.lifecycle.Schedule;
+import org.apache.maven.lifecycle.Scheduling;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Kristian Rosenvold
+ */
+
+public class DefaultLifecyclesStub {
+    public static DefaultLifecycles createDefaultLifeCycles() {
+        final Lifecycle lifecycle1 = new Lifecycle("abc", Arrays.asList("compile"),null );
+        final Lifecycle lifecycle2 = new Lifecycle("abc", Arrays.asList("test"), null);
+        final List<Lifecycle> lifeCycles = Arrays.asList(lifecycle1, lifecycle2);
+        final List<Scheduling> schedulingList = getSchedulingList();
+        final DefaultLifecycles defaultLifecycles = new DefaultLifecycles(lifeCycles, schedulingList);
+        try {
+            defaultLifecycles.initialize();
+        } catch (InitializationException e) {
+            throw new RuntimeException(e);
+        }
+        return defaultLifecycles;
+    }
+
+    public static List<Scheduling> getSchedulingList() {
+        return  Arrays.asList(new Scheduling("default", Arrays.asList(new Schedule("compile", false, true, false), new Schedule("test", false, false, true))));
+    }
+}
\ No newline at end of file
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifeCyclePluginAnalyzerStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifeCyclePluginAnalyzerStub.java
new file mode 100644
index 0000000..805e6be
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifeCyclePluginAnalyzerStub.java
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal.stub;
+
+import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginExecution;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class LifeCyclePluginAnalyzerStub implements LifeCyclePluginAnalyzer {
+    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging) {
+        Set<Plugin> plugins;
+
+        // NOTE: The upper-case packaging name is intentional, that's a special hinting mode used for certain tests
+        if ( "JAR".equals( packaging ) )
+        {
+            plugins = new LinkedHashSet<Plugin>();
+
+            plugins.add( newPlugin( "maven-compiler-plugin", "compile", "testCompile" ) );
+            plugins.add( newPlugin( "maven-resources-plugin", "resources", "testResources" ) );
+            plugins.add( newPlugin( "maven-surefire-plugin", "test" ) );
+            plugins.add( newPlugin( "maven-jar-plugin", "jar" ) );
+            plugins.add( newPlugin( "maven-install-plugin", "install" ) );
+            plugins.add( newPlugin( "maven-deploy-plugin", "deploy" ) );
+        }
+        else
+        {
+            plugins = Collections.emptySet();
+        }
+
+        return plugins;
+    }
+    
+    private Plugin newPlugin( String artifactId, String... goals )
+    {
+        Plugin plugin = new Plugin();
+
+        plugin.setGroupId( "org.apache.maven.plugins" );
+        plugin.setArtifactId( artifactId );
+
+        for ( String goal : goals )
+        {
+            PluginExecution pluginExecution = new PluginExecution();
+            pluginExecution.setId( "default-" + goal );
+            pluginExecution.addGoal( goal );
+            plugin.addExecution( pluginExecution );
+        }
+
+        return plugin;
+    }
+
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleExecutionPlanCalculatorStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleExecutionPlanCalculatorStub.java
new file mode 100644
index 0000000..f69d041
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleExecutionPlanCalculatorStub.java
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal.stub;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.LifecycleNotFoundException;
+import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.lifecycle.internal.ExecutionPlanItem;
+import org.apache.maven.lifecycle.internal.LifecycleExecutionPlanCalculator;
+import org.apache.maven.lifecycle.internal.ProjectBuild;
+import org.apache.maven.lifecycle.internal.ProjectBuildList;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+
+import java.util.*;
+
+/**
+ * @author <a href="mailto:kristian@zenior.no">Kristian Rosenvold</a>
+ */
+public class LifecycleExecutionPlanCalculatorStub implements LifecycleExecutionPlanCalculator {
+    public final static MojoDescriptor CLEAN = createMojoDescriptor("clean");
+    public final static MojoDescriptor VALIDATE = createMojoDescriptor("validate");
+    public final static MojoDescriptor TEST_COMPILE = createMojoDescriptor("test-compile");
+    public final static MojoDescriptor PROCESS_TEST_RESOURCES = createMojoDescriptor("process-test-resources");
+    public final static MojoDescriptor PROCESS_RESOURCES = createMojoDescriptor("process-resources");
+    public final static MojoDescriptor COMPILE = createMojoDescriptor("compile");
+    public final static MojoDescriptor TEST = createMojoDescriptor("test");
+    public final static MojoDescriptor PACKAGE = createMojoDescriptor("package");
+    public final static MojoDescriptor INSTALL = createMojoDescriptor("install");
+
+    public int getNumberOfExceutions(ProjectBuildList projectBuildList) throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException, NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
+        int result = 0;
+        for (ProjectBuild projectBuild : projectBuildList) {
+            MavenExecutionPlan plan = calculateExecutionPlan(projectBuild.getSession(), projectBuild.getProject(), projectBuild.getTaskSegment().getTasks());
+            result += plan.size();
+        }
+        return result;
+    }
+    
+    public MavenExecutionPlan calculateExecutionPlan(MavenSession session, MavenProject project, List<Object> tasks) throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException {
+        if (project.equals(ProjectDependencyGraphStub.A)){
+            return getProjectAExceutionPlan();
+        }
+        if (project.equals(ProjectDependencyGraphStub.B)){
+            return getProjectBExecutionPlan();
+        }
+        // The remaining are basically "for future expansion"
+        List<MojoExecution> me = new ArrayList<MojoExecution>();
+        me.add( createMojoExecution(new Plugin(), "resources", "default-resources",  PROCESS_RESOURCES));
+        me.add( createMojoExecution(new Plugin(), "compile", "default-compile",  COMPILE));
+        return new MavenExecutionPlan(getScopes(), getScopes(), DefaultLifecyclesStub.createDefaultLifeCycles().createExecutionPlanItem( project, me));
+    }
+
+    public static MavenExecutionPlan getProjectAExceutionPlan() throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException {
+        List<MojoExecution> me = new ArrayList<MojoExecution>();
+        me.add( createMojoExecution(new Plugin(), "enforce", "enforce-versions", VALIDATE));
+        me.add( createMojoExecution(new Plugin(), "resources", "default-resources",  PROCESS_RESOURCES));
+        me.add( createMojoExecution(new Plugin(), "compile", "default-compile",  COMPILE));
+        me.add( createMojoExecution(new Plugin(), "testResources", "default-testResources",  PROCESS_TEST_RESOURCES));
+        me.add( createMojoExecution(new Plugin(), "testCompile", "default-testCompile",  TEST_COMPILE));
+        me.add( createMojoExecution(new Plugin(), "test", "default-test",  TEST));
+        me.add( createMojoExecution(new Plugin(), "war", "default-war",  PACKAGE));
+        me.add( createMojoExecution(new Plugin(), "install", "default-install",  INSTALL));
+        final List<ExecutionPlanItem> executionPlanItem = DefaultLifecyclesStub.createDefaultLifeCycles().createExecutionPlanItem(ProjectDependencyGraphStub.A.getExecutionProject(), me);
+        return new MavenExecutionPlan(getScopes(), getScopes(), executionPlanItem);
+    }
+
+    public static MavenExecutionPlan getProjectBExecutionPlan() throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException {
+        List<MojoExecution> me = new ArrayList<MojoExecution>();
+        me.add( createMojoExecution(new Plugin(), "enforce", "enforce-versions", VALIDATE));
+        me.add( createMojoExecution(new Plugin(), "resources", "default-resources",  PROCESS_RESOURCES));
+        me.add( createMojoExecution(new Plugin(), "compile", "default-compile",  COMPILE));
+        me.add( createMojoExecution(new Plugin(), "testResources", "default-testResources",  PROCESS_TEST_RESOURCES));
+        me.add( createMojoExecution(new Plugin(), "testCompile", "default-testCompile",  TEST_COMPILE));
+        me.add( createMojoExecution(new Plugin(), "test", "default-test",  TEST));
+        final List<ExecutionPlanItem> planItem = DefaultLifecyclesStub.createDefaultLifeCycles().createExecutionPlanItem(ProjectDependencyGraphStub.B.getExecutionProject(), me);
+        return new MavenExecutionPlan(getScopes(), getScopes(), planItem);
+    }
+
+    private static MojoExecution createMojoExecution( Plugin plugin, String goal, String executionId, MojoDescriptor mojoDescriptor){
+        MojoExecution result= new MojoExecution(plugin, goal, executionId);
+        result.setConfiguration( new Xpp3Dom(executionId + "-" + goal));
+        result.setMojoDescriptor(mojoDescriptor);
+        return result;
+
+    }
+
+     public static MojoDescriptor createMojoDescriptor(String phaseName) {
+        final MojoDescriptor mojoDescriptor = new MojoDescriptor();
+        mojoDescriptor.setPhase(phaseName);
+        final PluginDescriptor descriptor = new PluginDescriptor();
+        descriptor.setArtifactId("artifact." + phaseName);
+        mojoDescriptor.setPluginDescriptor(descriptor);
+        return mojoDescriptor;
+    }
+    
+
+    public static Set<String> getScopes(){
+        return new HashSet<String>(Arrays.asList("compile"));
+    }
+    
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleTaskSegmentCalculatorStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleTaskSegmentCalculatorStub.java
new file mode 100644
index 0000000..5423e80
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleTaskSegmentCalculatorStub.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal.stub;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.internal.GoalTask;
+import org.apache.maven.lifecycle.internal.LifecycleTask;
+import org.apache.maven.lifecycle.internal.LifecycleTaskSegmentCalculator;
+import org.apache.maven.lifecycle.internal.TaskSegment;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Kristian Rosenvold
+ */
+
+public class LifecycleTaskSegmentCalculatorStub implements LifecycleTaskSegmentCalculator {
+    public static final String clean = "clean";
+    public static final String aggr = "aggr";
+    public static final String install = "install";
+    public List<TaskSegment> calculateTaskSegments(MavenSession session, List<String> tasks) throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException, PluginVersionResolutionException {
+        List<TaskSegment> taskSegments = new ArrayList<TaskSegment>(tasks.size());
+
+        TaskSegment currentSegment = null;
+
+        for (String task : tasks) {
+            if (aggr.equals(task)) {
+                MojoDescriptor mojoDescriptor = LifecycleExecutionPlanCalculatorStub.createMojoDescriptor(task);
+
+                boolean aggregating = true;
+
+                if (currentSegment == null || currentSegment.isAggregating() != aggregating) {
+                    currentSegment = new TaskSegment(aggregating);
+                    taskSegments.add(currentSegment);
+                }
+
+                currentSegment.getTasks().add(new GoalTask(mojoDescriptor));
+            } else {
+                // lifecycle phase
+               if (currentSegment == null || currentSegment.isAggregating()) {
+                    currentSegment = new TaskSegment(false);
+                    taskSegments.add(currentSegment);
+                }
+                currentSegment.getTasks().add(new LifecycleTask(task));
+            }
+        }
+
+        return taskSegments;
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LoggerStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LoggerStub.java
new file mode 100644
index 0000000..98a6255
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LoggerStub.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal.stub;
+
+import org.codehaus.plexus.logging.Logger;
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class LoggerStub implements Logger {
+    public void debug(String s) {
+    }
+
+    public void debug(String s, Throwable throwable) {
+    }
+
+    public boolean isDebugEnabled() {
+        return true; 
+    }
+
+    public void info(String s) {
+    }
+
+    public void info(String s, Throwable throwable) {
+    }
+
+    public boolean isInfoEnabled() {
+        return true;
+    }
+
+    public void warn(String s) {
+    }
+
+    public void warn(String s, Throwable throwable) {
+    }
+
+    public boolean isWarnEnabled() {
+        return true;
+    }
+
+    public void error(String s) {
+    }
+
+    public void error(String s, Throwable throwable) {
+    }
+
+    public boolean isErrorEnabled() {
+        return true;
+    }
+
+    public void fatalError(String s) {
+    }
+
+    public void fatalError(String s, Throwable throwable) {
+    }
+
+    public boolean isFatalErrorEnabled() {
+        return true;
+    }
+
+    public Logger getChildLogger(String s) {
+        return null;  
+    }
+
+    public int getThreshold() {
+        return 0;
+    }
+
+    public void setThreshold(int i) {
+
+    }
+
+    public String getName() {
+        return "StubLogger";
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/MojoExecutorStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/MojoExecutorStub.java
new file mode 100644
index 0000000..dd1508f
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/MojoExecutorStub.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal.stub;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.LifecycleExecutionException;
+import org.apache.maven.lifecycle.internal.DependencyContext;
+import org.apache.maven.lifecycle.internal.MojoExecutor;
+import org.apache.maven.lifecycle.internal.ProjectIndex;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class MojoExecutorStub extends MojoExecutor { // This is being lazy instead of making interface
+    public List<MojoExecution> executions = Collections.synchronizedList(new ArrayList<MojoExecution>());
+    @Override
+    public void execute(MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex, DependencyContext dependencyContext) throws LifecycleExecutionException {
+        executions.add( mojoExecution);
+    }
+
+    public static MojoDescriptor createMojoDescriptor(String mojoDescription) {
+        final PluginDescriptor descriptor = new PluginDescriptor();
+        descriptor.setArtifactId(mojoDescription);
+        final MojoDescriptor mojoDescriptor = new MojoDescriptor();
+        mojoDescriptor.setDescription(mojoDescription);
+        mojoDescriptor.setPluginDescriptor(descriptor);
+        return mojoDescriptor;
+    }
+
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginPrefixResolverStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginPrefixResolverStub.java
new file mode 100644
index 0000000..7e17b9e
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginPrefixResolverStub.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal.stub;
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.prefix.PluginPrefixRequest;
+import org.apache.maven.plugin.prefix.PluginPrefixResolver;
+import org.apache.maven.plugin.prefix.PluginPrefixResult;
+
+/**
+ * @author Kristian Rosenvold
+ */
+
+public class PluginPrefixResolverStub implements PluginPrefixResolver {
+    public PluginPrefixResult resolve(PluginPrefixRequest request) throws NoPluginFoundForPrefixException {
+        return new PluginPrefixResult(){
+            public String getGroupId() {
+                return "com.foobar";
+            }
+
+            public String getArtifactId() {
+               return  "bazbaz";
+            }
+
+            public ArtifactRepository getRepository() {
+                return null;
+            }
+        };
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginVersionResolverStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginVersionResolverStub.java
new file mode 100644
index 0000000..8cd196b
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginVersionResolverStub.java
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal.stub;
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.plugin.version.PluginVersionRequest;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+import org.apache.maven.plugin.version.PluginVersionResolver;
+import org.apache.maven.plugin.version.PluginVersionResult;
+
+/**
+ * @author Kristian Rosenvold
+ */
+
+public class PluginVersionResolverStub implements PluginVersionResolver {
+
+    public PluginVersionResult resolve(PluginVersionRequest request) throws PluginVersionResolutionException {
+        return new PluginVersionResult(){
+            public String getVersion() {
+                return "0.42";
+            }
+
+            public ArtifactRepository getRepository() {
+                return null;
+            }
+        };
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependenciesResolverStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependenciesResolverStub.java
new file mode 100644
index 0000000..3ab7d42
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependenciesResolverStub.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal.stub;
+
+import org.apache.maven.ProjectDependenciesResolver;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class ProjectDependenciesResolverStub implements ProjectDependenciesResolver {
+    public Set<Artifact> resolve(MavenProject project, Collection<String> scopesToResolve, MavenSession session) throws ArtifactResolutionException, ArtifactNotFoundException {
+        return new HashSet<Artifact>();
+   }
+
+    public Set<Artifact> resolve(MavenProject project, Collection<String> scopesToCollect, Collection<String> scopesToResolve, MavenSession session) throws ArtifactResolutionException, ArtifactNotFoundException {
+        return new HashSet<Artifact>();
+    }
+
+    public Set<Artifact> resolve(Collection<? extends MavenProject> projects, Collection<String> scopes, MavenSession session) throws ArtifactResolutionException, ArtifactNotFoundException {
+        return new HashSet<Artifact>();
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStub.java
new file mode 100644
index 0000000..ef5b389
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStub.java
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal.stub;
+
+import org.apache.maven.execution.*;
+import org.apache.maven.lifecycle.DefaultLifecycles;
+import org.apache.maven.lifecycle.LifecycleNotFoundException;
+import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
+import org.apache.maven.lifecycle.MavenExecutionPlan;
+import org.apache.maven.lifecycle.internal.*;
+import org.apache.maven.plugin.*;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+import org.apache.maven.project.MavenProject;
+
+import java.util.*;
+
+/**
+ * A stub dependency graph that is custom made for testing concurrent build graph evaluations.
+ *
+ * Implements a graph as follows:
+ * A has no dependencies
+ * B depends on A
+ * C depends on A
+ * X depends on B & C
+ * Y depends on B
+ * Z depends on C
+
+ * @author Kristian Rosenvold
+ */
+public class ProjectDependencyGraphStub implements ProjectDependencyGraph {
+    public static final MavenProject A = new MavenProject();
+    public static final MavenProject B = new MavenProject();
+    public static final MavenProject C = new MavenProject();
+    public static final MavenProject X = new MavenProject();
+    public static final MavenProject Y = new MavenProject();
+    public static final MavenProject Z = new MavenProject();
+    public static final MavenProject UNKNOWN = new MavenProject();
+
+    static {
+        A.setArtifactId("A");
+        B.setArtifactId("B");
+        C.setArtifactId("C");
+        X.setArtifactId("X");
+        Y.setArtifactId("Y");
+        Z.setArtifactId("Z");
+    }
+
+    // This should probably be moved to a separate stub
+
+    public static List<ProjectBuild>  getSegmentEnds(List<ProjectBuild> list){
+        return Arrays.asList( list.get(2), list.get(4));
+
+    }
+
+    public static ProjectBuildList getProjectBuildList(MavenSession session) throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException, NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
+        final List<ProjectBuild> list = getProjectBuilds(session);
+        return new ProjectBuildList(list, getSegmentEnds(list));
+
+    }
+
+    public static  List<ProjectBuild> getProjectBuilds(MavenSession session) throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException, NoPluginFoundForPrefixException, PluginNotFoundException, MojoNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
+        List<ProjectBuild> projectBuilds = new ArrayList<ProjectBuild>();
+
+        projectBuilds.add(createProjectBuild(A, session));
+        projectBuilds.add(createProjectBuild(B, session));
+        projectBuilds.add(createProjectBuild(C, session));
+        projectBuilds.add(createProjectBuild(X, session));
+        projectBuilds.add(createProjectBuild(Y, session));
+        projectBuilds.add(createProjectBuild(Z, session));
+        return projectBuilds;
+    }
+
+    private static ProjectBuild createProjectBuild(MavenProject mavenProject, MavenSession session) throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException, NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
+        final MavenSession session1 = session.clone();
+        final TaskSegment taskSegment = createTaskSegment();
+        LifecycleExecutionPlanCalculatorStub lifecycleExecutionPlanCalculator = new LifecycleExecutionPlanCalculatorStub();
+        final MavenExecutionPlan plan = lifecycleExecutionPlanCalculator.calculateExecutionPlan(session1, mavenProject, taskSegment.getTasks());
+        final DefaultLifecycles cycles = DefaultLifecyclesStub.createDefaultLifeCycles();
+        return new ProjectBuild(A, taskSegment, session1);
+    }
+
+
+    private static TaskSegment createTaskSegment(){
+        TaskSegment result = new TaskSegment(false);
+        result.getTasks().add( new GoalTask(MojoExecutorStub.createMojoDescriptor("t1")));
+        result.getTasks().add( new GoalTask(MojoExecutorStub.createMojoDescriptor("t2")));
+        return result;
+    }
+
+    class Dependency {
+        MavenProject dependant;
+        MavenProject dependency;
+
+        Dependency(MavenProject dependant, MavenProject dependency) {
+            this.dependant = dependant;
+            this.dependency = dependency;
+        }
+        void addIfDownstream( MavenProject mavenProject, List<MavenProject> result){
+            if (dependency == mavenProject) result.add( dependant);
+        }
+
+        void addIfUpstreamOf( MavenProject mavenProject, List<MavenProject> result){
+            if (dependant == mavenProject) result.add( dependency); // All projects are the statics from this class
+        }
+    }
+    private List<Dependency> getDependencies(){
+        List<Dependency> dependencies = new ArrayList<Dependency>();
+        dependencies.add( new Dependency( B,A));
+        dependencies.add( new Dependency( C,A));
+        dependencies.add( new Dependency( X,B));
+        dependencies.add( new Dependency( X,C));
+        dependencies.add( new Dependency( Y,B));
+        dependencies.add( new Dependency( Z,C));
+        return dependencies;
+    }
+
+    public List<MavenProject> getSortedProjects() {
+        return Arrays.asList(A, B, C, X, Y, Z); // I'm not entirely sure about the order but this shold do...
+    }
+
+    public List<MavenProject> getDownstreamProjects(MavenProject project, boolean transitive) {
+        if (transitive) throw new RuntimeException("Not implemented yet");
+        List<MavenProject> result = new ArrayList<MavenProject>();
+        for ( Dependency dependency : getDependencies()){
+            dependency.addIfDownstream( project, result);
+        }
+        return result;
+    }
+
+    public List<MavenProject> getUpstreamProjects(MavenProject project, boolean transitive) {
+        if (transitive) throw new RuntimeException("Not implemented yet");
+        List<MavenProject> result = new ArrayList<MavenProject>();
+        final List<Dependency> dependencies = getDependencies();
+        for ( Dependency dependency : dependencies){
+            dependency.addIfUpstreamOf( project, result);
+        }
+        return result;
+    }
+
+    public static MavenSession getMavenSession(MavenProject mavenProject) {
+        final MavenSession session = getMavenSession();
+        session.setCurrentProject( mavenProject);
+        return session;
+    }
+
+    public static MavenSession getMavenSession() {
+        final DefaultMavenExecutionResult defaultMavenExecutionResult = new DefaultMavenExecutionResult();
+        MavenExecutionRequest mavenExecutionRequest = new DefaultMavenExecutionRequest();
+        mavenExecutionRequest.setExecutionListener( new AbstractExecutionListener());
+        mavenExecutionRequest.setGoals( Arrays.asList("clean","aggr", "install"));
+        final MavenSession session = new MavenSession(null, mavenExecutionRequest, defaultMavenExecutionResult);
+        final ProjectDependencyGraphStub dependencyGraphStub = new ProjectDependencyGraphStub();
+        session.setProjectDependencyGraph(dependencyGraphStub);
+        session.setProjects( dependencyGraphStub.getSortedProjects());
+        return session;
+    }
+
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStubTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStubTest.java
new file mode 100644
index 0000000..27a8f3c
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStubTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.lifecycle.internal.stub;
+
+import junit.framework.TestCase;
+import org.apache.maven.project.MavenProject;
+
+import java.util.List;
+
+
+/**
+ * Tests the stub. Yeah, I know.
+ * @author Kristian Rosenvold
+ */
+
+public class ProjectDependencyGraphStubTest extends TestCase {
+    public void testADependencies(){
+        ProjectDependencyGraphStub stub = new ProjectDependencyGraphStub();
+        final List<MavenProject> mavenProjects = stub.getUpstreamProjects(ProjectDependencyGraphStub.A, false);
+        assertEquals( 0, mavenProjects.size());
+    }
+
+    public void testBDepenencies(ProjectDependencyGraphStub stub) {
+        final List<MavenProject> bProjects = stub.getUpstreamProjects(ProjectDependencyGraphStub.B, false);
+        assertEquals( 1, bProjects.size());
+        assertTrue(bProjects.contains( ProjectDependencyGraphStub.A));
+    }
+
+    public void testCDepenencies(ProjectDependencyGraphStub stub) {
+        final List<MavenProject> cProjects = stub.getUpstreamProjects(ProjectDependencyGraphStub.C, false);
+        assertEquals( 1, cProjects.size());
+        assertTrue(cProjects.contains( ProjectDependencyGraphStub.C));
+    }
+    public void testXDepenencies(ProjectDependencyGraphStub stub) {
+        final List<MavenProject> cProjects = stub.getUpstreamProjects(ProjectDependencyGraphStub.X, false);
+        assertEquals( 2, cProjects.size());
+        assertTrue(cProjects.contains( ProjectDependencyGraphStub.C));
+        assertTrue(cProjects.contains( ProjectDependencyGraphStub.B));
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java b/maven-core/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java
index 135b3e8..70ab6c9 100644
--- a/maven-core/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java
+++ b/maven-core/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java
@@ -55,7 +55,7 @@ public class EmptyLifecycleExecutor
         throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
         MojoNotFoundException
     {
-        return new MavenExecutionPlan( Collections.<MojoExecution> emptyList(), null, null );
+        return new MavenExecutionPlan(null, null, null );
     }
 
     public void execute( MavenSession session )
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/ExecutionEventLogger.java b/maven-embedder/src/main/java/org/apache/maven/cli/ExecutionEventLogger.java
index a517e16..f20d0b9 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/ExecutionEventLogger.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/ExecutionEventLogger.java
@@ -202,7 +202,9 @@ class ExecutionEventLogger
 
         long time = finish.getTime() - session.getRequest().getStartTime().getTime();
 
-        logger.info( "Total time: " + getFormattedTime( time ) );
+        String wallClock = session.getRequest().isWeave() ? " (Wall Clock)" : "";
+
+        logger.info( "Total time: " + getFormattedTime( time ) + wallClock);
 
         logger.info( "Finished at: " + finish );
 
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
index e717c3d..f80589e 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
@@ -71,6 +71,8 @@ public class MavenCli
 {
     public static final String LOCAL_REPO_PROPERTY = "maven.repo.local";
 
+    public static final String WEAVE_THREADS = "maven.threads.experimental";
+
     public static final String userHome = System.getProperty( "user.home" );
 
     public static final File userMavenConfigurationHome = new File( userHome, ".m2" );
@@ -875,6 +877,13 @@ public class MavenCli
             request.setLocalRepositoryPath( localRepoProperty );
         }
 
+
+        final String weaveConfiguration = request.getSystemProperties().getProperty(MavenCli.WEAVE_THREADS);
+        if (weaveConfiguration != null){
+            request.setWeaveConfiguration(weaveConfiguration);
+        }
+
+
         return request;
     }
 
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java
index 9707c94..ee08fb0 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java
@@ -134,27 +134,20 @@ public class StringSearchModelInterpolator
             }
             else if ( isQualifiedForInterpolation( cls ) )
             {
-                Field[] fields = fieldsByClass.get( cls );
-                if ( fields == null )
+                Field[] fields = getFields(cls);
+                for (Field currentField : fields)
                 {
-                    fields = cls.getDeclaredFields();
-                    fieldsByClass.put( cls, fields );
-                }
-
-                for ( int i = 0; i < fields.length; i++ )
-                {
-                    Class<?> type = fields[i].getType();
-                    if ( isQualifiedForInterpolation( fields[i], type ) )
+                    Class<?> type = currentField.getType();
+                    if ( isQualifiedForInterpolation( currentField, type ) )
                     {
-                        boolean isAccessible = fields[i].isAccessible();
-                        fields[i].setAccessible( true );
-                        try
-                        {
+                        synchronized ( currentField){
+                            boolean isAccessible = currentField.isAccessible();
+                            currentField.setAccessible( true );
                             try
                             {
                                 if ( String.class == type )
                                 {
-                                    String value = (String) fields[i].get( target );
+                                    String value = (String) currentField.get( target );
                                     if ( value != null )
                                     {
                                         String interpolated =
@@ -163,13 +156,13 @@ public class StringSearchModelInterpolator
 
                                         if ( !interpolated.equals( value ) )
                                         {
-                                            fields[i].set( target, interpolated );
+                                            currentField.set( target, interpolated );
                                         }
                                     }
                                 }
                                 else if ( Collection.class.isAssignableFrom( type ) )
                                 {
-                                    Collection<Object> c = (Collection<Object>) fields[i].get( target );
+                                    Collection<Object> c = (Collection<Object>) currentField.get( target );
                                     if ( c != null && !c.isEmpty() )
                                     {
                                         List<Object> originalValues = new ArrayList<Object>( c );
@@ -225,7 +218,7 @@ public class StringSearchModelInterpolator
                                 }
                                 else if ( Map.class.isAssignableFrom( type ) )
                                 {
-                                    Map<Object, Object> m = (Map<Object, Object>) fields[i].get( target );
+                                    Map<Object, Object> m = (Map<Object, Object>) currentField.get( target );
                                     if ( m != null && !m.isEmpty() )
                                     {
                                         for ( Map.Entry<Object, Object> entry : m.entrySet() )
@@ -270,10 +263,10 @@ public class StringSearchModelInterpolator
                                 }
                                 else
                                 {
-                                    Object value = fields[i].get( target );
+                                    Object value = currentField.get( target );
                                     if ( value != null )
                                     {
-                                        if ( fields[i].getType().isArray() )
+                                        if ( currentField.getType().isArray() )
                                         {
                                             evaluateArray( value );
                                         }
@@ -286,18 +279,21 @@ public class StringSearchModelInterpolator
                             }
                             catch ( IllegalArgumentException e )
                             {
-                                problems.add( Severity.ERROR, "Failed to interpolate field: " + fields[i]
-                                    + " on class: " + cls.getName(), e );
+                                e.printStackTrace(System.err);
+
+                                problems.add( Severity.ERROR, "Failed to interpolate field3: " + currentField + " on class: "
+                                    + cls.getName(), e );
                             }
                             catch ( IllegalAccessException e )
                             {
-                                problems.add( Severity.ERROR, "Failed to interpolate field: " + fields[i]
-                                    + " on class: " + cls.getName(), e );
+                                e.printStackTrace(System.err);
+                                problems.add( Severity.ERROR, "Failed to interpolate field4: " + currentField + " on class: "
+                                    + cls.getName(), e );
+                            }
+                            finally
+                            {
+                                currentField.setAccessible( isAccessible );
                             }
-                        }
-                        finally
-                        {
-                            fields[i].setAccessible( isAccessible );
                         }
                     }
                 }
@@ -306,6 +302,20 @@ public class StringSearchModelInterpolator
             }
         }
 
+        private Field[] getFields(Class<?> cls) {
+            Field[] fields;
+            synchronized(fieldsByClass)
+            {
+                fields = fieldsByClass.get( cls );
+                if ( fields == null )
+                {
+                    fields = cls.getDeclaredFields();
+                    fieldsByClass.put( cls, fields );
+                }
+            }
+            return fields;
+        }
+
         private boolean isQualifiedForInterpolation( Class<?> cls )
         {
             return !cls.getPackage().getName().startsWith( "java" );
@@ -313,14 +323,17 @@ public class StringSearchModelInterpolator
 
         private boolean isQualifiedForInterpolation( Field field, Class<?> fieldType )
         {
-            if ( !fieldIsPrimitiveByClass.containsKey( fieldType ) )
+            synchronized ( fieldIsPrimitiveByClass)
             {
-                fieldIsPrimitiveByClass.put( fieldType, Boolean.valueOf( fieldType.isPrimitive() ) );
-            }
+                if ( !fieldIsPrimitiveByClass.containsKey( fieldType ) )
+                {
+                    fieldIsPrimitiveByClass.put( fieldType, Boolean.valueOf( fieldType.isPrimitive() ) );
+                }
 
-            if ( fieldIsPrimitiveByClass.get( fieldType ).booleanValue() )
-            {
-                return false;
+                if ( fieldIsPrimitiveByClass.get( fieldType ).booleanValue() )
+                {
+                    return false;
+                }
             }
 
 //            if ( fieldType.isPrimitive() )
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/AbstractModelInterpolatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/AbstractModelInterpolatorTest.java
new file mode 100644
index 0000000..9fbd874
--- /dev/null
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/AbstractModelInterpolatorTest.java
@@ -0,0 +1,419 @@
+package org.apache.maven.model.interpolation;
+
+/*
+ * 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.model.Build;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Organization;
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.Resource;
+import org.apache.maven.model.Scm;
+import org.apache.maven.model.building.DefaultModelBuildingRequest;
+import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.building.SimpleProblemCollector;
+import org.apache.maven.model.path.DefaultPathTranslator;
+import org.apache.maven.model.path.PathTranslator;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+import org.codehaus.plexus.PlexusTestCase;
+
+/**
+ * @author jdcasey
+ * @version $Id: AbstractModelInterpolatorTest.java 813569 2009-09-10 20:04:14Z jdcasey $
+ */
+public abstract class AbstractModelInterpolatorTest
+    extends PlexusTestCase
+{
+    private Properties context;
+    
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        context = new Properties();
+        context.put( "basedir", "myBasedir" );
+        context.put( "project.baseUri", "myBaseUri" );
+    }
+
+
+    private ModelBuildingRequest createModelBuildingRequest(Properties p) {
+        ModelBuildingRequest config = new DefaultModelBuildingRequest();
+        if (p!= null) config.setSystemProperties( p);
+        return config;
+    }
+    
+/*    public void testDefaultBuildTimestampFormatShouldParseTimeIn24HourFormat()
+    {
+        Calendar cal = Calendar.getInstance();
+        cal.set( Calendar.HOUR, 12 );
+        cal.set( Calendar.AM_PM, Calendar.AM );
+        
+        // just to make sure all the bases are covered...
+        cal.set( Calendar.HOUR_OF_DAY, 0 );
+        cal.set( Calendar.MINUTE, 16 );
+        cal.set( Calendar.YEAR, 1976 );
+        cal.set( Calendar.MONTH, Calendar.NOVEMBER );
+        cal.set( Calendar.DATE, 11 );
+        
+        Date firstTestDate = cal.getTime();
+        
+        cal.set( Calendar.HOUR, 11 );
+        cal.set( Calendar.AM_PM, Calendar.PM );
+        
+        // just to make sure all the bases are covered...
+        cal.set( Calendar.HOUR_OF_DAY, 23 );
+        
+        Date secondTestDate = cal.getTime();
+        
+        SimpleDateFormat format = new SimpleDateFormat( ModelInterpolator.DEFAULT_BUILD_TIMESTAMP_FORMAT );
+      assertEquals( "19761111-0016", format.format( firstTestDate ) );
+      assertEquals( "19761111-2316", format.format( secondTestDate ) );
+    }
+  */
+    public void testShouldNotThrowExceptionOnReferenceToNonExistentValue()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Scm scm = new Scm();
+        scm.setConnection( "${test}/somepath" );
+
+        model.setScm( scm );
+
+        ModelInterpolator interpolator = createInterpolator();
+        
+        Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+
+        assertEquals( "${test}/somepath", out.getScm().getConnection() );
+    }
+
+    /*
+
+    public void testShouldThrowExceptionOnRecursiveScmConnectionReference()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Scm scm = new Scm();
+        scm.setConnection( "${project.scm.connection}/somepath" );
+
+        model.setScm( scm );
+
+        try
+        {
+            ModelInterpolator interpolator = createInterpolator();
+            
+            Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+
+            fail( "The interpolator should not allow self-referencing expressions in POM." );
+        }
+        catch ( Exception e )
+        {
+
+        }
+    }
+    */
+
+    public void testShouldNotThrowExceptionOnReferenceToValueContainingNakedExpression()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Scm scm = new Scm();
+        scm.setConnection( "${test}/somepath" );
+
+        model.setScm( scm );
+
+        model.addProperty( "test", "test" );
+
+        ModelInterpolator interpolator = createInterpolator();
+        
+        Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+
+        assertEquals( "test/somepath", out.getScm().getConnection() );
+    }
+
+    public void testShouldInterpolateOrganizationNameCorrectly()
+        throws Exception
+    {
+        String orgName = "MyCo";
+
+        Model model = new Model();
+        model.setName( "${pom.organization.name} Tools" );
+
+        Organization org = new Organization();
+        org.setName( orgName );
+
+        model.setOrganization( org );
+
+        ModelInterpolator interpolator = createInterpolator();
+        
+        Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+
+        assertEquals( orgName + " Tools", out.getName() );
+    }
+
+    public void testShouldInterpolateDependencyVersionToSetSameAsProjectVersion()
+        throws Exception
+    {
+        Model model = new Model();
+        model.setVersion( "3.8.1" );
+
+        Dependency dep = new Dependency();
+        dep.setVersion( "${version}" );
+
+        model.addDependency( dep );
+
+        ModelInterpolator interpolator = createInterpolator();
+        
+        Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+
+        assertEquals( "3.8.1", ( (Dependency) out.getDependencies().get( 0 ) ).getVersion() );
+    }
+
+    public void testShouldNotInterpolateDependencyVersionWithInvalidReference()
+        throws Exception
+    {
+        Model model = new Model();
+        model.setVersion( "3.8.1" );
+
+        Dependency dep = new Dependency();
+        dep.setVersion( "${something}" );
+
+        model.addDependency( dep );
+
+        /*
+         // This is the desired behaviour, however there are too many crappy poms in the repo and an issue with the
+         // timing of executing the interpolation
+
+         try
+         {
+         new RegexBasedModelInterpolator().interpolate( model, context );
+         fail( "Should have failed to interpolate with invalid reference" );
+         }
+         catch ( ModelInterpolationException expected )
+         {
+         assertTrue( true );
+         }
+         */
+
+        ModelInterpolator interpolator = createInterpolator();
+        
+        Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+        
+        assertEquals( "${something}", ( (Dependency) out.getDependencies().get( 0 ) ).getVersion() );
+    }
+
+    public void testTwoReferences()
+        throws Exception
+    {
+        Model model = new Model();
+        model.setVersion( "3.8.1" );
+        model.setArtifactId( "foo" );
+
+        Dependency dep = new Dependency();
+        dep.setVersion( "${artifactId}-${version}" );
+
+        model.addDependency( dep );
+
+        ModelInterpolator interpolator = createInterpolator();
+        
+        Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+
+        assertEquals( "foo-3.8.1", ( (Dependency) out.getDependencies().get( 0 ) ).getVersion() );
+    }
+
+/*public void testBasedir()
+        throws Exception
+    {
+        Model model = new Model();
+        model.setVersion( "3.8.1" );
+        model.setArtifactId( "foo" );
+
+        Repository repository = new Repository();
+
+        repository.setUrl( "file://localhost/${basedir}/temp-repo" );
+
+        model.addRepository( repository );
+
+        ModelInterpolator interpolator = createInterpolator();
+        
+        Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+
+        assertEquals( "file://localhost/myBasedir/temp-repo", ( (Repository) out.getRepositories().get( 0 ) ).getUrl() );
+    }
+  */
+/*    public void testBaseUri()
+        throws Exception
+    {
+        Model model = new Model();
+        model.setVersion( "3.8.1" );
+        model.setArtifactId( "foo" );
+
+        Repository repository = new Repository();
+
+        repository.setUrl( "${project.baseUri}/temp-repo" );
+
+        model.addRepository( repository );
+
+        ModelInterpolator interpolator = createInterpolator();
+
+        Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+
+        assertEquals( "myBaseUri/temp-repo", ( (Repository) out.getRepositories().get( 0 ) ).getUrl() );
+    }
+  */
+    public void testEnvars()
+        throws Exception
+    {
+         Properties context = new Properties();
+
+        context.put( "env.HOME", "/path/to/home" );
+
+        Model model = new Model();
+
+        Properties modelProperties = new Properties();
+
+        modelProperties.setProperty( "outputDirectory", "${env.HOME}" );
+
+        model.setProperties( modelProperties );
+
+        ModelInterpolator interpolator = createInterpolator();
+        
+        Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+
+        assertEquals( "/path/to/home", out.getProperties().getProperty( "outputDirectory" ) );
+    }
+
+    public void testEnvarExpressionThatEvaluatesToNullReturnsTheLiteralString()
+        throws Exception
+    {
+        Properties envars = new Properties();
+
+        Model model = new Model();
+
+        Properties modelProperties = new Properties();
+
+        modelProperties.setProperty( "outputDirectory", "${env.DOES_NOT_EXIST}" );
+
+        model.setProperties( modelProperties );
+
+        ModelInterpolator interpolator = createInterpolator();
+        
+        Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+
+        assertEquals( out.getProperties().getProperty( "outputDirectory" ), "${env.DOES_NOT_EXIST}" );
+    }
+
+    public void testExpressionThatEvaluatesToNullReturnsTheLiteralString()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Properties modelProperties = new Properties();
+
+        modelProperties.setProperty( "outputDirectory", "${DOES_NOT_EXIST}" );
+
+        model.setProperties( modelProperties );
+
+        ModelInterpolator interpolator = createInterpolator();
+        
+        Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+        
+        assertEquals( out.getProperties().getProperty( "outputDirectory" ), "${DOES_NOT_EXIST}" );
+    }
+
+/*    public void testShouldInterpolateSourceDirectoryReferencedFromResourceDirectoryCorrectly()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Build build = new Build();
+        build.setSourceDirectory( "correct" );
+
+        Resource res = new Resource();
+        res.setDirectory( "${project.build.sourceDirectory}" );
+
+        build.addResource( res );
+
+        Resource res2 = new Resource();
+        res2.setDirectory( "${pom.build.sourceDirectory}" );
+
+        build.addResource( res2 );
+
+        Resource res3 = new Resource();
+        res3.setDirectory( "${build.sourceDirectory}" );
+
+        build.addResource( res3 );
+
+        model.setBuild( build );
+
+        ModelInterpolator interpolator = createInterpolator();
+        
+        Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+        
+        List outResources = out.getBuild().getResources();
+        Iterator resIt = outResources.iterator();
+
+        assertEquals( build.getSourceDirectory(), ( (Resource) resIt.next() ).getDirectory() );
+        assertEquals( build.getSourceDirectory(), ( (Resource) resIt.next() ).getDirectory() );
+        assertEquals( build.getSourceDirectory(), ( (Resource) resIt.next() ).getDirectory() );
+    }
+  */
+/*public void testShouldInterpolateUnprefixedBasedirExpression()
+        throws Exception
+    {
+        File basedir = new File( "/test/path" );
+        Model model = new Model();
+        Dependency dep = new Dependency();
+        dep.setSystemPath( "${basedir}/artifact.jar" );
+
+        model.addDependency( dep );
+
+        ModelInterpolator interpolator = createInterpolator();
+        
+        Model result = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
+
+        List rDeps = result.getDependencies();
+        assertNotNull( rDeps );
+        assertEquals( 1, rDeps.size() );
+        assertEquals( new File( basedir, "artifact.jar" ).getAbsolutePath(), new File( ( (Dependency) rDeps.get( 0 ) )
+            .getSystemPath() ).getAbsolutePath() );
+    }
+  */  
+
+    protected abstract ModelInterpolator createInterpolator( PathTranslator translator )
+        throws Exception;
+
+    protected abstract ModelInterpolator createInterpolator()
+        throws Exception;
+
+
+}
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringSearchModelInterpolatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringSearchModelInterpolatorTest.java
new file mode 100644
index 0000000..3f11333
--- /dev/null
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringSearchModelInterpolatorTest.java
@@ -0,0 +1,424 @@
+package org.apache.maven.model.interpolation;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.model.building.DefaultModelBuildingRequest;
+import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.building.SimpleProblemCollector;
+import org.codehaus.plexus.PlexusTestCase;
+
+/**
+ * @author jdcasey
+ * @version $Id: StringSearchModelInterpolatorTest.java 708543 2008-10-28 11:54:17Z bentmann $
+ */
+public class StringSearchModelInterpolatorTest
+    extends AbstractModelInterpolatorTest 
+{
+
+
+    protected ModelInterpolator interpolator;
+
+    @Override
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+        interpolator =  lookup(ModelInterpolator.class);
+    }
+
+
+    protected ModelInterpolator createInterpolator( org.apache.maven.model.path.PathTranslator translator )
+        throws Exception
+    {
+        return this.interpolator;
+    }
+
+    protected ModelInterpolator createInterpolator()
+        throws Exception
+    {
+        return this.interpolator;
+    }
+
+    public void testInterpolateStringArray()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Properties p = new Properties();
+        p.setProperty( "key", "value" );
+        p.setProperty( "key2", "value2" );
+
+        String[] values = { "${key}", "${key2}" };
+
+        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
+
+        ModelBuildingRequest config = createModelBuildingRequest(p);
+
+        interpolator.interpolateObject( values, model, new File( "." ), config, new SimpleProblemCollector()  );
+
+        assertEquals( "value", values[0] );
+        assertEquals( "value2", values[1] );
+    }
+
+    private ModelBuildingRequest createModelBuildingRequest(Properties p) {
+        ModelBuildingRequest config = new DefaultModelBuildingRequest();
+        config.setSystemProperties( p);
+        return config;
+    }
+
+    public void testInterpolateObjectWithStringArrayField()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Properties p = new Properties();
+        p.setProperty( "key", "value" );
+        p.setProperty( "key2", "value2" );
+
+        String[] values = { "${key}", "${key2}" };
+
+        ObjectWithStringArrayField obj = new ObjectWithStringArrayField( values );
+
+        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
+
+        ModelBuildingRequest config = createModelBuildingRequest(p);
+
+        interpolator.interpolateObject( obj, model, new File( "." ), config, new SimpleProblemCollector()  );
+
+        assertEquals( "value", obj.values[0] );
+        assertEquals( "value2", obj.values[1] );
+    }
+
+    public void testInterpolateObjectWithStringListField()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Properties p = new Properties();
+        p.setProperty( "key", "value" );
+        p.setProperty( "key2", "value2" );
+
+        List values = new ArrayList();
+        values.add( "${key}" );
+        values.add( "${key2}" );
+
+        ObjectWithListField obj = new ObjectWithListField( values );
+
+        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
+
+        ModelBuildingRequest config = createModelBuildingRequest(p);
+
+        interpolator.interpolateObject( obj, model, new File( "." ), config, new SimpleProblemCollector() );
+
+        assertEquals( "value", obj.values.get( 0 ) );
+        assertEquals( "value2", obj.values.get( 1 ) );
+    }
+
+    public void testInterpolateObjectWithStringListFieldAndOneLiteralValue()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Properties p = new Properties();
+        p.setProperty( "key", "value" );
+        p.setProperty( "key2", "value2" );
+
+        List values = new ArrayList();
+        values.add( "key" );
+        values.add( "${key2}" );
+
+        ObjectWithListField obj = new ObjectWithListField( values );
+
+        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
+
+        ModelBuildingRequest config = createModelBuildingRequest(p);
+
+        interpolator.interpolateObject( obj, model, new File( "." ), config, new SimpleProblemCollector() );
+
+        assertEquals( "key", obj.values.get( 0 ) );
+        assertEquals( "value2", obj.values.get( 1 ) );
+    }
+
+    public void testInterpolateObjectWithUnmodifiableStringListField()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Properties p = new Properties();
+        p.setProperty( "key", "value" );
+        p.setProperty( "key2", "value2" );
+
+        List values = Collections.unmodifiableList( Collections.singletonList( "${key}" ) );
+
+        ObjectWithListField obj = new ObjectWithListField( values );
+
+        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
+
+        ModelBuildingRequest config = createModelBuildingRequest(p);
+
+
+        interpolator.interpolateObject( obj, model, new File( "." ), config,  new SimpleProblemCollector() );
+
+        assertEquals( "${key}", obj.values.get( 0 ) );
+    }
+
+    public void testInterpolateObjectWithStringArrayListField()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Properties p = new Properties();
+        p.setProperty( "key", "value" );
+        p.setProperty( "key2", "value2" );
+        p.setProperty( "key3", "value3" );
+        p.setProperty( "key4", "value4" );
+
+        List values = new ArrayList();
+        values.add( new String[] { "${key}", "${key2}" } );
+        values.add( new String[] { "${key3}", "${key4}" } );
+
+        ObjectWithListField obj = new ObjectWithListField( values );
+
+        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
+
+        ModelBuildingRequest config = createModelBuildingRequest(p);
+
+        interpolator.interpolateObject( obj, model, new File( "." ), config,  new SimpleProblemCollector() );
+
+        assertEquals( "value", ( (String[]) obj.values.get( 0 ) )[0] );
+        assertEquals( "value2", ( (String[]) obj.values.get( 0 ) )[1] );
+        assertEquals( "value3", ( (String[]) obj.values.get( 1 ) )[0] );
+        assertEquals( "value4", ( (String[]) obj.values.get( 1 ) )[1] );
+    }
+
+    public void testInterpolateObjectWithStringToStringMapField()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Properties p = new Properties();
+        p.setProperty( "key", "value" );
+        p.setProperty( "key2", "value2" );
+
+        Map values = new HashMap();
+        values.put( "key", "${key}" );
+        values.put( "key2", "${key2}" );
+
+        ObjectWithMapField obj = new ObjectWithMapField( values );
+
+        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
+
+        ModelBuildingRequest config = createModelBuildingRequest(p);
+
+        interpolator.interpolateObject( obj, model, new File( "." ), config, new SimpleProblemCollector() );
+
+        assertEquals( "value", obj.values.get( "key" ) );
+        assertEquals( "value2", obj.values.get( "key2" ) );
+    }
+
+    public void testInterpolateObjectWithStringToStringMapFieldAndOneLiteralValue()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Properties p = new Properties();
+        p.setProperty( "key", "value" );
+        p.setProperty( "key2", "value2" );
+
+        Map values = new HashMap();
+        values.put( "key", "val" );
+        values.put( "key2", "${key2}" );
+
+        ObjectWithMapField obj = new ObjectWithMapField( values );
+
+        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
+
+        ModelBuildingRequest config = createModelBuildingRequest(p);
+
+        interpolator.interpolateObject( obj, model, new File( "." ), config, new SimpleProblemCollector() );
+
+        assertEquals( "val", obj.values.get( "key" ) );
+        assertEquals( "value2", obj.values.get( "key2" ) );
+    }
+
+    public void testInterpolateObjectWithUnmodifiableStringToStringMapField()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Properties p = new Properties();
+        p.setProperty( "key", "value" );
+        p.setProperty( "key2", "value2" );
+
+        Map values = Collections.unmodifiableMap( Collections.singletonMap( "key", "${key}" ) );
+
+        ObjectWithMapField obj = new ObjectWithMapField( values );
+
+        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
+
+        ModelBuildingRequest config = createModelBuildingRequest(p);
+
+        interpolator.interpolateObject( obj, model, new File( "." ), config, new SimpleProblemCollector() );
+
+        assertEquals( "${key}", obj.values.get( "key" ) );
+    }
+
+    public void testInterpolateObjectWithStringToStringArrayMapField()
+        throws Exception
+    {
+        Model model = new Model();
+
+        Properties p = new Properties();
+        p.setProperty( "key", "value" );
+        p.setProperty( "key2", "value2" );
+        p.setProperty( "key3", "value3" );
+        p.setProperty( "key4", "value4" );
+
+        Map values = new HashMap();
+        values.put( "key", new String[] { "${key}", "${key2}" } );
+        values.put( "key2", new String[] { "${key3}", "${key4}" } );
+
+        ObjectWithMapField obj = new ObjectWithMapField( values );
+
+        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
+
+        ModelBuildingRequest config = createModelBuildingRequest(p);
+
+        interpolator.interpolateObject( obj, model, new File( "." ), config, new SimpleProblemCollector() );
+
+        assertEquals( "value", ( (String[]) obj.values.get( "key" ) )[0] );
+        assertEquals( "value2", ( (String[]) obj.values.get( "key" ) )[1] );
+        assertEquals( "value3", ( (String[]) obj.values.get( "key2" ) )[0] );
+        assertEquals( "value4", ( (String[]) obj.values.get( "key2" ) )[1] );
+    }
+
+
+    public void testConcurrentInterpolation() throws Exception {
+        final Model model = new Model();
+
+        Properties p = new Properties();
+        p.setProperty( "key", "value" );
+        p.setProperty( "key2", "value2" );
+        p.setProperty( "key3", "value3" );
+        p.setProperty( "key4", "value4" );
+
+        List values = new ArrayList();
+        values.add( new String[] { "${key}", "${key2}" } );
+        values.add( new String[] { "${key3}", "${key4}" } );
+        List values2 = new ArrayList();
+        values.add( new String[] { "${key}", "${key2}" } );
+        values.add( new String[] { "${key3}", "${key4}" } );
+        List values3 = new ArrayList();
+        values.add( new String[] { "${key}", "${key2}" } );
+        values.add( new String[] { "${key3}", "${key4}" } );
+
+        // There is an interesting issue here; if I send three identical collections into the three Lists in "obj", like this:
+        // final ObjectWithMixedProtection obj = new ObjectWithMixedProtection( values, values, values );
+        // I will have concurrency issues on the interpolation of the individual collections, since current
+        // synchronization is per-field and not per-underlying object.
+        // If this turns out to be a realistic use case, we will need to synchronize on the underlying collection
+        // in the interpolate method.
+
+        final ObjectWithMixedProtection obj = new ObjectWithMixedProtection( values, values2, values3 );
+        final StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
+        final ModelBuildingRequest config = createModelBuildingRequest(p);
+
+
+        int numItems = 250;
+        final CountDownLatch countDownLatch = new CountDownLatch(1);
+
+        List<Future<SimpleProblemCollector>>  futures = new ArrayList<Future<SimpleProblemCollector>>();
+        for (int i = 0; i < numItems; i++){
+            Callable<SimpleProblemCollector> future = new Callable<SimpleProblemCollector>() {
+                public SimpleProblemCollector call() throws Exception {
+                    countDownLatch.await();
+                    final SimpleProblemCollector collector = new SimpleProblemCollector();
+                    interpolator.interpolateObject( obj, model, new File( "." ), config, collector);
+                    return collector;
+                };
+            };
+            FutureTask<SimpleProblemCollector> task = new FutureTask<SimpleProblemCollector>(future);
+            futures.add ( task);
+            new Thread( task).start();
+        }
+        countDownLatch.countDown(); // Start all the threads
+        for(Future<SimpleProblemCollector> result : futures){
+            result.get(); // This should not fail. ArrayIndexOutOfBoundsException are typical indication of threading issues
+        }
+    }
+
+
+    private static final class ObjectWithStringArrayField
+    {
+        private final String[] values;
+
+        public ObjectWithStringArrayField( String[] values )
+        {
+            this.values = values;
+        }
+    }
+
+    private static final class ObjectWithListField
+    {
+        private final List values;
+
+        public ObjectWithListField( List values )
+        {
+            this.values = values;
+        }
+    }
+
+    private static final class ObjectWithMapField
+    {
+        private final Map values;
+
+        public ObjectWithMapField( Map values )
+        {
+            this.values = values;
+        }
+    }
+
+    private static final class ObjectWithMixedProtection
+    {
+        private List values1;
+        protected List values2;
+        List values3;
+
+        private ObjectWithMixedProtection(List values1, List values2, List values3) {
+            this.values1 = values1;
+            this.values2 = values2;
+            this.values3 = values3;
+        }
+    }
+
+}

