You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ah...@apache.org on 2015/04/01 02:24:02 UTC

[20/50] [abbrv] maven git commit: MNG-5775 Make the project graph building code pluggable to allow for new/different implementations.

http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java
----------------------------------------------------------------------
diff --git a/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java b/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java
new file mode 100644
index 0000000..e2caaeb
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.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.graph;
+
+import junit.framework.TestCase;
+import org.apache.maven.execution.ProjectDependencyGraph;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.project.DuplicateProjectException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.dag.CycleDetectedException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Kristian Rosenvold
+ */
+public class DefaultProjectDependencyGraphTest
+    extends TestCase
+{
+
+    private final MavenProject aProject = createA();
+
+    private final MavenProject depender1 = createProject( Arrays.asList( toDependency( aProject ) ), "depender1" );
+
+    private final MavenProject depender2 = createProject( Arrays.asList( toDependency( aProject ) ), "depender2" );
+
+    private final MavenProject depender3 = createProject( Arrays.asList( toDependency( aProject ) ), "depender3" );
+
+    private final MavenProject depender4 =
+        createProject( Arrays.asList( toDependency( aProject ), toDependency( depender3 ) ), "depender4" );
+
+    private final MavenProject transitiveOnly =
+        createProject( Arrays.asList( toDependency( depender3 ) ), "depender5" );
+
+    public void testGetSortedProjects()
+        throws DuplicateProjectException, CycleDetectedException
+    {
+        ProjectDependencyGraph graph = new DefaultProjectDependencyGraph( Arrays.asList( depender1, aProject ) );
+        final List<MavenProject> sortedProjects = graph.getSortedProjects();
+        assertEquals( aProject, sortedProjects.get( 0 ) );
+        assertEquals( depender1, sortedProjects.get( 1 ) );
+    }
+
+    public void testVerifyExpectedParentStructure()
+        throws CycleDetectedException, DuplicateProjectException
+    {
+        // This test verifies the baseline structure used in susequent tests. If this fails, the rest will fail.
+        ProjectDependencyGraph graph = threeProjectsDependingOnASingle();
+        final List<MavenProject> sortedProjects = graph.getSortedProjects();
+        assertEquals( aProject, sortedProjects.get( 0 ) );
+        assertEquals( depender1, sortedProjects.get( 1 ) );
+        assertEquals( depender2, sortedProjects.get( 2 ) );
+        assertEquals( depender3, sortedProjects.get( 3 ) );
+    }
+
+    public void testVerifyThatDownsteamProjectsComeInSortedOrder()
+        throws CycleDetectedException, DuplicateProjectException
+    {
+        final List<MavenProject> downstreamProjects =
+            threeProjectsDependingOnASingle().getDownstreamProjects( aProject, true );
+        assertEquals( depender1, downstreamProjects.get( 0 ) );
+        assertEquals( depender2, downstreamProjects.get( 1 ) );
+        assertEquals( depender3, downstreamProjects.get( 2 ) );
+    }
+
+    public void testTransitivesInOrder()
+        throws CycleDetectedException, DuplicateProjectException
+    {
+        final ProjectDependencyGraph graph =
+            new DefaultProjectDependencyGraph( Arrays.asList( depender1, depender4, depender2, depender3, aProject ) );
+
+        final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, true );
+        assertEquals( depender1, downstreamProjects.get( 0 ) );
+        assertEquals( depender3, downstreamProjects.get( 1 ) );
+        assertEquals( depender4, downstreamProjects.get( 2 ) );
+        assertEquals( depender2, downstreamProjects.get( 3 ) );
+    }
+
+    public void testNonTransitivesInOrder()
+        throws CycleDetectedException, DuplicateProjectException
+    {
+        final ProjectDependencyGraph graph =
+            new DefaultProjectDependencyGraph( Arrays.asList( depender1, depender4, depender2, depender3, aProject ) );
+
+        final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, false );
+        assertEquals( depender1, downstreamProjects.get( 0 ) );
+        assertEquals( depender3, downstreamProjects.get( 1 ) );
+        assertEquals( depender4, downstreamProjects.get( 2 ) );
+        assertEquals( depender2, downstreamProjects.get( 3 ) );
+    }
+
+    public void testWithTranistiveOnly()
+        throws CycleDetectedException, DuplicateProjectException
+    {
+        final ProjectDependencyGraph graph = new DefaultProjectDependencyGraph(
+            Arrays.asList( depender1, transitiveOnly, depender2, depender3, aProject ) );
+
+        final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, true );
+        assertEquals( depender1, downstreamProjects.get( 0 ) );
+        assertEquals( depender3, downstreamProjects.get( 1 ) );
+        assertEquals( transitiveOnly, downstreamProjects.get( 2 ) );
+        assertEquals( depender2, downstreamProjects.get( 3 ) );
+    }
+
+    public void testWithMissingTranistiveOnly()
+        throws CycleDetectedException, DuplicateProjectException
+    {
+        final ProjectDependencyGraph graph = new DefaultProjectDependencyGraph(
+            Arrays.asList( depender1, transitiveOnly, depender2, depender3, aProject ) );
+
+        final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, false );
+        assertEquals( depender1, downstreamProjects.get( 0 ) );
+        assertEquals( depender3, downstreamProjects.get( 1 ) );
+        assertEquals( depender2, downstreamProjects.get( 2 ) );
+    }
+
+    public void testGetUpstreamProjects()
+        throws CycleDetectedException, DuplicateProjectException
+    {
+        ProjectDependencyGraph graph = threeProjectsDependingOnASingle();
+        final List<MavenProject> downstreamProjects = graph.getUpstreamProjects( depender1, true );
+        assertEquals( aProject, downstreamProjects.get( 0 ) );
+    }
+
+    private ProjectDependencyGraph threeProjectsDependingOnASingle()
+        throws CycleDetectedException, DuplicateProjectException
+    {
+        return new DefaultProjectDependencyGraph( Arrays.asList( depender1, depender2, depender3, aProject ) );
+    }
+
+    private static MavenProject createA()
+    {
+        MavenProject result = new MavenProject();
+        result.setGroupId( "org.apache" );
+        result.setArtifactId( "A" );
+        result.setVersion( "1.2" );
+        return result;
+    }
+
+    static Dependency toDependency( MavenProject mavenProject )
+    {
+        final Dependency dependency = new Dependency();
+        dependency.setArtifactId( mavenProject.getArtifactId() );
+        dependency.setGroupId( mavenProject.getGroupId() );
+        dependency.setVersion( mavenProject.getVersion() );
+        return dependency;
+    }
+
+    private static MavenProject createProject( List<Dependency> dependencies, String artifactId )
+    {
+        MavenProject result = new MavenProject();
+        result.setGroupId( "org.apache" );
+        result.setArtifactId( artifactId );
+        result.setVersion( "1.2" );
+        result.setDependencies( dependencies );
+        return result;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java
----------------------------------------------------------------------
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java
index 04be08b..99b07e3 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
@@ -409,6 +409,11 @@ public class LifecycleExecutorTest
             {
                 return Collections.emptyList();
             }
+            
+            public java.util.List<MavenProject> getAllSortedProjects()
+            {
+                return Collections.emptyList();
+            }
         } );
 
         final List<String> log = new ArrayList<String>();

http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/pom.xml
----------------------------------------------------------------------
diff --git a/maven-model-builder/pom.xml b/maven-model-builder/pom.xml
index 738f64f..186e207 100644
--- a/maven-model-builder/pom.xml
+++ b/maven-model-builder/pom.xml
@@ -51,7 +51,10 @@
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-builder-support</artifactId>
     </dependency>
-
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.eclipse.sisu</groupId>
       <artifactId>org.eclipse.sisu.plexus</artifactId>

http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
----------------------------------------------------------------------
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
index 80effb1..52b3c9c 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
@@ -19,6 +19,10 @@ package org.apache.maven.model.building;
  * under the License.
  */
 
+
+import static org.apache.maven.model.building.Result.error;
+import static org.apache.maven.model.building.Result.newResult;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -63,6 +67,7 @@ import org.apache.maven.model.profile.ProfileSelector;
 import org.apache.maven.model.resolution.InvalidRepositoryException;
 import org.apache.maven.model.resolution.ModelResolver;
 import org.apache.maven.model.resolution.UnresolvableModelException;
+import org.apache.maven.model.resolution.WorkspaceModelResolver;
 import org.apache.maven.model.superpom.SuperPomProvider;
 import org.apache.maven.model.validation.ModelValidator;
 import org.codehaus.plexus.component.annotations.Component;
@@ -241,8 +246,8 @@ public class DefaultModelBuilder
         DefaultProfileActivationContext profileActivationContext = getProfileActivationContext( request );
 
         problems.setSource( "(external profiles)" );
-        List<Profile> activeExternalProfiles =
-            profileSelector.getActiveProfiles( request.getProfiles(), profileActivationContext, problems );
+        List<Profile> activeExternalProfiles = profileSelector.getActiveProfiles( request.getProfiles(),
+                                                                                  profileActivationContext, problems );
 
         result.setActiveExternalProfiles( activeExternalProfiles );
 
@@ -258,7 +263,11 @@ public class DefaultModelBuilder
         }
 
         // read and validate raw model
-        Model inputModel = readModel( request.getModelSource(), request.getPomFile(), request, problems );
+        Model inputModel = request.getRawModel();
+        if ( inputModel == null )
+        {
+            inputModel = readModel( request.getModelSource(), request.getPomFile(), request, problems );
+        }
 
         problems.setRootModel( inputModel );
 
@@ -272,11 +281,12 @@ public class DefaultModelBuilder
         {
             lineage.add( currentData );
 
-            Model tmpModel = currentData.getModel();
-
-            Model rawModel = tmpModel.clone();
+            Model rawModel = currentData.getModel();
             currentData.setRawModel( rawModel );
 
+            Model tmpModel = rawModel.clone();
+            currentData.setModel( tmpModel );
+
             problems.setSource( tmpModel );
 
             // model normalization
@@ -284,8 +294,8 @@ public class DefaultModelBuilder
 
             profileActivationContext.setProjectProperties( tmpModel.getProperties() );
 
-            List<Profile> activePomProfiles =
-                profileSelector.getActiveProfiles( rawModel.getProfiles(), profileActivationContext, problems );
+            List<Profile> activePomProfiles = profileSelector.getActiveProfiles( rawModel.getProfiles(),
+                                                                                 profileActivationContext, problems );
             currentData.setActiveProfiles( activePomProfiles );
 
             Map<String, Activation> interpolatedActivations = getProfileActivations( rawModel, false );
@@ -320,13 +330,13 @@ public class DefaultModelBuilder
             }
             else if ( currentData == resultData )
             { // First iteration - add initial parent id after version resolution.
-                currentData.setGroupId( currentData.getRawModel().getGroupId() == null
-                                            ? parentData.getGroupId()
-                                            : currentData.getRawModel().getGroupId() );
+                currentData.setGroupId( currentData.getRawModel().getGroupId() == null ? parentData.getGroupId()
+                                                                                      : currentData.getRawModel()
+                                                                                          .getGroupId() );
 
-                currentData.setVersion( currentData.getRawModel().getVersion() == null
-                                            ? parentData.getVersion()
-                                            : currentData.getRawModel().getVersion() );
+                currentData.setVersion( currentData.getRawModel().getVersion() == null ? parentData.getVersion()
+                                                                                      : currentData.getRawModel()
+                                                                                          .getVersion() );
 
                 currentData.setArtifactId( currentData.getRawModel().getArtifactId() );
                 parentIds.add( currentData.getId() );
@@ -345,9 +355,8 @@ public class DefaultModelBuilder
                 }
                 message += parentData.getId();
 
-                problems.add(
-                    new ModelProblemCollectorRequest( ModelProblem.Severity.FATAL, ModelProblem.Version.BASE ).
-                    setMessage( message ) );
+                problems.add( new ModelProblemCollectorRequest( ModelProblem.Severity.FATAL, ModelProblem.Version.BASE )
+                    .setMessage( message ) );
 
                 throw problems.newModelBuildingException();
             }
@@ -376,7 +385,7 @@ public class DefaultModelBuilder
         modelUrlNormalizer.normalize( resultModel, request );
 
         // Now the fully interpolated model is available: reconfigure the resolver
-        configureResolver( request.getModelResolver(), resultModel, problems , true );
+        configureResolver( request.getModelResolver(), resultModel, problems, true );
 
         resultData.setGroupId( resultModel.getGroupId() );
         resultData.setArtifactId( resultModel.getArtifactId() );
@@ -469,6 +478,23 @@ public class DefaultModelBuilder
         return result;
     }
 
+    @Override
+    public Result<? extends Model> buildRawModel( File pomFile, int validationLevel, boolean locationTracking )
+    {
+        final ModelBuildingRequest request = new DefaultModelBuildingRequest().setValidationLevel( validationLevel )
+            .setLocationTracking( locationTracking );
+        final DefaultModelProblemCollector collector = 
+            new DefaultModelProblemCollector( new DefaultModelBuildingResult() );
+        try
+        {
+            return newResult( readModel( null, pomFile, request, collector ), collector.getProblems() );
+        }
+        catch ( ModelBuildingException e )
+        {
+            return error( collector.getProblems() );
+        }
+    }
+
     private Model readModel( ModelSource modelSource, File pomFile, ModelBuildingRequest request,
                              DefaultModelProblemCollector problems )
         throws ModelBuildingException
@@ -524,14 +550,14 @@ public class DefaultModelBuilder
                 if ( pomFile != null )
                 {
                     problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.V20 )
-                            .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() )
-                            .setException( e ) );
+                        .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() )
+                        .setException( e ) );
                 }
                 else
                 {
                     problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 )
-                            .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() )
-                            .setException( e ) );
+                        .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() )
+                        .setException( e ) );
                 }
             }
 
@@ -544,8 +570,8 @@ public class DefaultModelBuilder
         catch ( ModelParseException e )
         {
             problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
-                    .setMessage( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage() )
-                    .setException( e ) );
+                .setMessage( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage() )
+                .setException( e ) );
             throw problems.newModelBuildingException();
         }
         catch ( IOException e )
@@ -564,8 +590,7 @@ public class DefaultModelBuilder
                 }
             }
             problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
-                    .setMessage( "Non-readable POM " + modelSource.getLocation() + ": " + msg )
-                    .setException( e ) );
+                .setMessage( "Non-readable POM " + modelSource.getLocation() + ": " + msg ).setException( e ) );
             throw problems.newModelBuildingException();
         }
 
@@ -621,9 +646,8 @@ public class DefaultModelBuilder
             catch ( InvalidRepositoryException e )
             {
                 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                        .setMessage( "Invalid repository " + repository.getId() + ": " + e.getMessage() )
-                        .setLocation( repository.getLocation( "" ) )
-                        .setException( e ) );
+                    .setMessage( "Invalid repository " + repository.getId() + ": " + e.getMessage() )
+                    .setLocation( repository.getLocation( "" ) ).setException( e ) );
             }
         }
     }
@@ -675,7 +699,8 @@ public class DefaultModelBuilder
             if ( versions.get( key ) == null && managedVersions.get( key ) == null )
             {
                 InputLocation location = plugins.get( key ).getLocation( "" );
-                problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 )
+                problems
+                    .add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 )
                         .setMessage( "'build.plugins.plugin.version' for " + key + " is missing." )
                         .setLocation( location ) );
             }
@@ -800,9 +825,9 @@ public class DefaultModelBuilder
             if ( !"pom".equals( parentModel.getPackaging() ) )
             {
                 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                        .setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel )
+                    .setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel )
                                      + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"" )
-                        .setLocation( parentModel.getLocation( "packaging" ) ) );
+                    .setLocation( parentModel.getLocation( "packaging" ) ) );
             }
         }
         else
@@ -817,20 +842,52 @@ public class DefaultModelBuilder
                                          DefaultModelProblemCollector problems )
         throws ModelBuildingException
     {
-        ModelSource candidateSource = getParentPomFile( childModel, childSource );
-
-        if ( candidateSource == null )
+        final Parent parent = childModel.getParent();
+        final ModelSource candidateSource;
+        final Model candidateModel;
+        final WorkspaceModelResolver resolver = request.getWorkspaceModelResolver();
+        if ( resolver == null )
         {
-            return null;
-        }
+            candidateSource = getParentPomFile( childModel, childSource );
+
+            if ( candidateSource == null )
+            {
+                return null;
+            }
+
+            File pomFile = null;
+            if ( candidateSource instanceof FileModelSource )
+            {
+                pomFile = ( (FileModelSource) candidateSource ).getPomFile();
+            }
 
-        File pomFile = null;
-        if ( candidateSource instanceof FileModelSource )
+            candidateModel = readModel( candidateSource, pomFile, request, problems );
+        }
+        else
         {
-            pomFile = ( (FileModelSource) candidateSource ).getPomFile();
+            try
+            {
+                candidateModel =
+                    resolver.resolveRawModel( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
+            }
+            catch ( UnresolvableModelException e )
+            {
+                problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) //
+                .setMessage( e.getMessage().toString() ).setLocation( parent.getLocation( "" ) ).setException( e ) );
+                throw problems.newModelBuildingException();
+            }
+            if ( candidateModel == null )
+            {
+                return null;
+            }
+            candidateSource = new FileModelSource( candidateModel.getPomFile() );
         }
 
-        Model candidateModel = readModel( candidateSource, pomFile, request, problems );
+        //
+        // TODO:jvz Why isn't all this checking the job of the duty of the workspace resolver, we know that we
+        // have a model that is suitable, yet more checks are done here and the one for the version is problematic
+        // before because with parents as ranges it will never work in this scenario.
+        //
 
         String groupId = candidateModel.getGroupId();
         if ( groupId == null && candidateModel.getParent() != null )
@@ -844,8 +901,6 @@ public class DefaultModelBuilder
             version = candidateModel.getParent().getVersion();
         }
 
-        Parent parent = childModel.getParent();
-
         if ( groupId == null || !groupId.equals( parent.getGroupId() ) || artifactId == null
             || !artifactId.equals( parent.getArtifactId() ) )
         {
@@ -861,15 +916,19 @@ public class DefaultModelBuilder
 
             problems.setSource( childModel );
             problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.BASE )
-                    .setMessage( buffer.toString() )
-                    .setLocation( parent.getLocation( "" ) ) );
-            return null;
-        }
-        if ( version == null || !version.equals( parent.getVersion() ) )
-        {
+                .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ) );
             return null;
         }
 
+        //
+        // Here we just need to know that a version is fine to use but this validation we can do in our workspace
+        // resolver.
+        //
+
+        /*
+         * if ( version == null || !version.equals( parent.getVersion() ) ) { return null; }
+         */
+
         ModelData parentData = new ModelData( candidateSource, candidateModel, groupId, artifactId, version );
 
         return parentData;
@@ -944,9 +1003,7 @@ public class DefaultModelBuilder
             }
 
             problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
-                    .setMessage( buffer.toString() )
-                    .setLocation( parent.getLocation( "" ) )
-                    .setException( e ) );
+                .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ).setException( e ) );
             throw problems.newModelBuildingException();
         }
 
@@ -969,18 +1026,17 @@ public class DefaultModelBuilder
         {
             if ( childModel.getVersion() == null )
             {
-                problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 ).
-                    setMessage( "Version must be a constant" ).
-                    setLocation( childModel.getLocation( "" ) ) );
+                problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
+                    .setMessage( "Version must be a constant" ).setLocation( childModel.getLocation( "" ) ) );
 
             }
             else
             {
                 if ( childModel.getVersion().indexOf( "${" ) > -1 )
                 {
-                    problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 ).
-                        setMessage( "Version must be a constant" ).
-                        setLocation( childModel.getLocation( "version" ) ) );
+                    problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
+                        .setMessage( "Version must be a constant" )
+                        .setLocation( childModel.getLocation( "version" ) ) );
 
                 }
             }
@@ -1013,7 +1069,8 @@ public class DefaultModelBuilder
 
         importIds.add( importing );
 
-        ModelResolver modelResolver = request.getModelResolver();
+        final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver();
+        final ModelResolver modelResolver = request.getModelResolver();
 
         ModelBuildingRequest importRequest = null;
 
@@ -1037,25 +1094,25 @@ public class DefaultModelBuilder
             if ( groupId == null || groupId.length() <= 0 )
             {
                 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                        .setMessage( "'dependencyManagement.dependencies.dependency.groupId' for "
-                                        + dependency.getManagementKey() + " is missing." )
-                        .setLocation( dependency.getLocation( "" ) ) );
+                    .setMessage( "'dependencyManagement.dependencies.dependency.groupId' for "
+                                     + dependency.getManagementKey() + " is missing." )
+                    .setLocation( dependency.getLocation( "" ) ) );
                 continue;
             }
             if ( artifactId == null || artifactId.length() <= 0 )
             {
                 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                        .setMessage( "'dependencyManagement.dependencies.dependency.artifactId' for "
-                                        + dependency.getManagementKey() + " is missing." )
-                        .setLocation( dependency.getLocation( "" ) ) );
+                    .setMessage( "'dependencyManagement.dependencies.dependency.artifactId' for "
+                                     + dependency.getManagementKey() + " is missing." )
+                    .setLocation( dependency.getLocation( "" ) ) );
                 continue;
             }
             if ( version == null || version.length() <= 0 )
             {
                 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                        .setMessage( "'dependencyManagement.dependencies.dependency.version' for "
-                                        + dependency.getManagementKey() + " is missing." )
-                        .setLocation( dependency.getLocation( "" ) ) );
+                    .setMessage( "'dependencyManagement.dependencies.dependency.version' for "
+                                     + dependency.getManagementKey() + " is missing." )
+                    .setLocation( dependency.getLocation( "" ) ) );
                 continue;
             }
 
@@ -1074,67 +1131,85 @@ public class DefaultModelBuilder
                 continue;
             }
 
-            DependencyManagement importMngt =
-                getCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT );
+            DependencyManagement importMngt = getCache( request.getModelCache(), groupId, artifactId, version,
+                                                        ModelCacheTag.IMPORT );
 
             if ( importMngt == null )
             {
-                if ( modelResolver == null )
+                if ( workspaceResolver == null && modelResolver == null )
                 {
                     throw new IllegalArgumentException( "no model resolver provided, cannot resolve import POM "
                         + ModelProblemUtils.toId( groupId, artifactId, version ) + " for POM "
                         + ModelProblemUtils.toSourceHint( model ) );
                 }
 
-                ModelSource importSource;
-                try
+                Model importModel = null;
+                if ( workspaceResolver != null )
                 {
-                    importSource = modelResolver.resolveModel( groupId, artifactId, version );
+                    try
+                    {
+                        importModel = workspaceResolver.resolveEffectiveModel( groupId, artifactId, version );
+                    }
+                    catch ( UnresolvableModelException e )
+                    {
+                        problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
+                            .setMessage( e.getMessage().toString() ).setException( e ) );
+                        continue;
+                    }
                 }
-                catch ( UnresolvableModelException e )
+
+                // no workspace resolver or workspace resolver returned null (i.e. model not in workspace)
+                if ( importModel == null )
                 {
-                    StringBuilder buffer = new StringBuilder( 256 );
-                    buffer.append( "Non-resolvable import POM" );
-                    if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) )
+                    final ModelSource importSource;
+                    try
                     {
-                        buffer.append( " " ).append( ModelProblemUtils.toId( groupId, artifactId, version ) );
+                        importSource = modelResolver.resolveModel( groupId, artifactId, version );
                     }
-                    buffer.append( ": " ).append( e.getMessage() );
+                    catch ( UnresolvableModelException e )
+                    {
+                        StringBuilder buffer = new StringBuilder( 256 );
+                        buffer.append( "Non-resolvable import POM" );
+                        if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) )
+                        {
+                            buffer.append( " " ).append( ModelProblemUtils.toId( groupId, artifactId, version ) );
+                        }
+                        buffer.append( ": " ).append( e.getMessage() );
 
-                    problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                            .setMessage( buffer.toString() )
-                            .setLocation( dependency.getLocation( "" ) )
+                        problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
+                            .setMessage( buffer.toString() ).setLocation( dependency.getLocation( "" ) )
                             .setException( e ) );
-                    continue;
-                }
+                        continue;
+                    }
 
-                if ( importRequest == null )
-                {
-                    importRequest = new DefaultModelBuildingRequest();
-                    importRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
-                    importRequest.setModelCache( request.getModelCache() );
-                    importRequest.setSystemProperties( request.getSystemProperties() );
-                    importRequest.setUserProperties( request.getUserProperties() );
-                    importRequest.setLocationTracking( request.isLocationTracking() );
-                }
+                    if ( importRequest == null )
+                    {
+                        importRequest = new DefaultModelBuildingRequest();
+                        importRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
+                        importRequest.setModelCache( request.getModelCache() );
+                        importRequest.setSystemProperties( request.getSystemProperties() );
+                        importRequest.setUserProperties( request.getUserProperties() );
+                        importRequest.setLocationTracking( request.isLocationTracking() );
+                    }
 
-                importRequest.setModelSource( importSource );
-                importRequest.setModelResolver( modelResolver.newCopy() );
+                    importRequest.setModelSource( importSource );
+                    importRequest.setModelResolver( modelResolver.newCopy() );
 
-                ModelBuildingResult importResult;
-                try
-                {
-                    importResult = build( importRequest );
-                }
-                catch ( ModelBuildingException e )
-                {
-                    problems.addAll( e.getProblems() );
-                    continue;
-                }
+                    final ModelBuildingResult importResult;
+                    try
+                    {
+                        importResult = build( importRequest );
+                    }
+                    catch ( ModelBuildingException e )
+                    {
+                        problems.addAll( e.getProblems() );
+                        continue;
+                    }
 
-                problems.addAll( importResult.getProblems() );
+                    problems.addAll( importResult.getProblems() );
 
-                Model importModel = importResult.getEffectiveModel();
+                    importModel = importResult.getEffectiveModel();
+                }
 
                 importMngt = importModel.getDependencyManagement();
 

http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java
----------------------------------------------------------------------
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java
index bd4211a..8b4a01b 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java
@@ -25,8 +25,10 @@ import java.util.Date;
 import java.util.List;
 import java.util.Properties;
 
+import org.apache.maven.model.Model;
 import org.apache.maven.model.Profile;
 import org.apache.maven.model.resolution.ModelResolver;
+import org.apache.maven.model.resolution.WorkspaceModelResolver;
 
 /**
  * Collects settings that control building of effective models.
@@ -37,6 +39,8 @@ public class DefaultModelBuildingRequest
     implements ModelBuildingRequest
 {
 
+    private Model rawModel;
+
     private File pomFile;
 
     private ModelSource modelSource;
@@ -67,6 +71,8 @@ public class DefaultModelBuildingRequest
 
     private ModelCache modelCache;
 
+    private WorkspaceModelResolver workspaceResolver;
+
     /**
      * Creates an empty request.
      */
@@ -373,4 +379,30 @@ public class DefaultModelBuildingRequest
         return this;
     }
 
+    @Override
+    public Model getRawModel()
+    {
+        return rawModel;
+    }
+
+    @Override
+    public ModelBuildingRequest setRawModel( Model rawModel )
+    {
+        this.rawModel = rawModel;
+        return this;
+    }
+
+    @Override
+    public WorkspaceModelResolver getWorkspaceModelResolver()
+    {
+        return workspaceResolver;
+    }
+
+    @Override
+    public ModelBuildingRequest setWorkspaceModelResolver( WorkspaceModelResolver workspaceResolver )
+    {
+        this.workspaceResolver = workspaceResolver;
+        return this;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java
----------------------------------------------------------------------
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java
index 7074689..c5c2cbf 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java
@@ -24,8 +24,10 @@ import java.util.Date;
 import java.util.List;
 import java.util.Properties;
 
+import org.apache.maven.model.Model;
 import org.apache.maven.model.Profile;
 import org.apache.maven.model.resolution.ModelResolver;
+import org.apache.maven.model.resolution.WorkspaceModelResolver;
 
 /**
  * A model building request that delegates all methods invocations to another request, meant for easy transformations by
@@ -254,4 +256,30 @@ class FilterModelBuildingRequest
         return this;
     }
 
-}
+    @Override
+    public Model getRawModel()
+    {
+        return request.getRawModel();
+    }
+
+    @Override
+    public ModelBuildingRequest setRawModel( Model rawModel )
+    {
+        request.setRawModel( rawModel );
+        return this;
+    }
+
+    @Override
+    public WorkspaceModelResolver getWorkspaceModelResolver()
+    {
+        return request.getWorkspaceModelResolver();
+    }
+
+    @Override
+    public ModelBuildingRequest setWorkspaceModelResolver( WorkspaceModelResolver workspaceResolver )
+    {
+        request.setWorkspaceModelResolver( workspaceResolver );
+        return this;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java
----------------------------------------------------------------------
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java
index c6c75f9..2a49a21 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java
@@ -19,6 +19,10 @@ package org.apache.maven.model.building;
  * under the License.
  */
 
+import java.io.File;
+
+import org.apache.maven.model.Model;
+
 /**
  * Builds the effective model from a POM.
  *
@@ -51,4 +55,13 @@ public interface ModelBuilder
     ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result )
         throws ModelBuildingException;
 
+    /**
+     * Performs only the part of {@link ModelBuilder#build(ModelBuildingRequest)} that loads the raw model
+     *
+     * @param request
+     * @return
+     * @throws ModelBuildingException
+     */
+    Result<? extends Model> buildRawModel( File pomFile, int validationLevel, boolean locationTracking );
+
 }

http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java
----------------------------------------------------------------------
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java
index 2a3a25a..c10274d 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java
@@ -24,8 +24,10 @@ import java.util.Date;
 import java.util.List;
 import java.util.Properties;
 
+import org.apache.maven.model.Model;
 import org.apache.maven.model.Profile;
 import org.apache.maven.model.resolution.ModelResolver;
+import org.apache.maven.model.resolution.WorkspaceModelResolver;
 
 /**
  * Collects settings that control the building of effective models.
@@ -63,6 +65,20 @@ public interface ModelBuildingRequest
     int VALIDATION_LEVEL_STRICT = VALIDATION_LEVEL_MAVEN_3_0;
 
     /**
+     * Gets the raw model to build. If not set, model source will be used to load raw model.
+     * 
+     * @return The raw model to build or {@code null} if not set.
+     */
+    Model getRawModel();
+
+    /**
+     * Set raw model.
+     *
+     * @param model
+     */
+    ModelBuildingRequest setRawModel( Model rawModel );
+
+    /**
      * Gets the source of the POM to process.
      *
      * @return The source of the POM or {@code null} if not set.
@@ -315,4 +331,8 @@ public interface ModelBuildingRequest
      */
     ModelBuildingRequest setModelCache( ModelCache modelCache );
 
-}
+    WorkspaceModelResolver getWorkspaceModelResolver();
+
+    ModelBuildingRequest setWorkspaceModelResolver( WorkspaceModelResolver workspaceResolver );
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/building/Result.java
----------------------------------------------------------------------
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/Result.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/Result.java
new file mode 100644
index 0000000..a962897
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/Result.java
@@ -0,0 +1,255 @@
+package org.apache.maven.model.building;
+
+/*
+ * 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 static com.google.common.base.Predicates.in;
+import static com.google.common.collect.Iterables.any;
+import static com.google.common.collect.Iterables.concat;
+import static com.google.common.collect.Iterables.transform;
+import static java.util.Collections.singleton;
+import static java.util.EnumSet.of;
+import static org.apache.maven.model.building.ModelProblem.Severity.ERROR;
+import static org.apache.maven.model.building.ModelProblem.Severity.FATAL;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.apache.maven.model.building.ModelProblem.Severity;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+/**
+ * There are various forms of results that are represented by this class:
+ * <ol>
+ * <li>success - in which case only the model field is set
+ * <li>success with warnings - model field + non-error model problems
+ * <li>error - no model, but diagnostics
+ * <li>error - (partial) model and diagnostics
+ * </ol>
+ * Could encode these variants as subclasses, but kept in one for now
+ * 
+ * @author bbusjaeger
+ * @param <T>
+ */
+public class Result<T>
+{
+
+    /**
+     * Success without warnings
+     * 
+     * @param model
+     * @return
+     */
+    public static <T> Result<T> success( T model )
+    {
+        return success( model, Collections.<ModelProblem>emptyList() );
+    }
+
+    /**
+     * Success with warnings
+     * 
+     * @param model
+     * @param problems
+     * @return
+     */
+    public static <T> Result<T> success( T model, Iterable<? extends ModelProblem> problems )
+    {
+        assert !hasErrors( problems );
+        return new Result<T>( false, model, problems );
+    }
+
+    /**
+     * Success with warnings
+     * 
+     * @param model
+     * @param results
+     * @return
+     */
+    public static <T> Result<T> success( T model, Result<?>... results )
+    {
+        return success( model, Iterables.concat( Iterables.transform( Arrays.asList( results ), GET_PROBLEMS ) ) );
+    }
+
+    /**
+     * Error with problems describing the cause
+     *
+     * @param problems
+     * @return
+     */
+    public static <T> Result<T> error( Iterable<? extends ModelProblem> problems )
+    {
+        return error( null, problems );
+    }
+
+    public static <T> Result<T> error( T model )
+    {
+        return error( model, Collections.<ModelProblem>emptyList() );
+    }
+
+    public static <T> Result<T> error( Result<?> result )
+    {
+        return error( result.getProblems() );
+    }
+
+    public static <T> Result<T> error( Result<?>... results )
+    {
+        return error( Iterables.concat( Iterables.transform( Arrays.asList( results ), GET_PROBLEMS ) ) );
+    }
+
+    /**
+     * Error with partial result and problems describing the cause
+     *
+     * @param model
+     * @param problems
+     * @return
+     */
+    public static <T> Result<T> error( T model, Iterable<? extends ModelProblem> problems )
+    {
+        return new Result<T>( true, model, problems );
+    }
+
+    /**
+     * New result - determine whether error or success by checking problems for errors
+     * 
+     * @param model
+     * @param problems
+     * @return
+     */
+    public static <T> Result<T> newResult( T model, Iterable<? extends ModelProblem> problems )
+    {
+        return new Result<T>( hasErrors( problems ), model, problems );
+    }
+
+    /**
+     * New result consisting of given result and new problem. Convenience for newResult(result.get(),
+     * concat(result.getProblems(),problems)).
+     * 
+     * @param result
+     * @param problem
+     * @return
+     */
+    public static <T> Result<T> addProblem( Result<T> result, ModelProblem problem )
+    {
+        return addProblems( result, singleton( problem ) );
+    }
+
+    /**
+     * New result that includes the given
+     *
+     * @param result
+     * @param problems
+     * @return
+     */
+    public static <T> Result<T> addProblems( Result<T> result, Iterable<? extends ModelProblem> problems )
+    {
+        return new Result<T>( result.hasErrors() || hasErrors( problems ), result.get(), concat( result.getProblems(),
+                                                                                                 problems ) );
+    }
+
+    public static <T> Result<T> addProblems( Result<T> result, Result<?>... results )
+    {
+        return addProblems( result, Iterables.concat( Iterables.transform( Arrays.asList( results ), GET_PROBLEMS ) ) );
+    }
+
+    /**
+     * Turns the given results into a single result by combining problems and models into single collection.
+     * 
+     * @param results
+     * @return
+     */
+    public static <T> Result<Iterable<T>> newResultSet( Iterable<? extends Result<? extends T>> results )
+    {
+        final boolean hasErrors = any( transform( results, new Function<Result<?>, Boolean>()
+        {
+            @Override
+            public Boolean apply( Result<?> input )
+            {
+                return input.hasErrors();
+            }
+        } ), Predicates.equalTo( true ) );
+        final Iterable<T> models = transform( results, new Function<Result<? extends T>, T>()
+        {
+            @Override
+            public T apply( Result<? extends T> input )
+            {
+                return input.get();
+            }
+        } );
+        final Iterable<ModelProblem> problems = concat( transform( results, GET_PROBLEMS ) );
+        return new Result<Iterable<T>>( hasErrors, models, problems );
+    }
+
+    // helper to determine if problems contain error
+    private static boolean hasErrors( Iterable<? extends ModelProblem> problems )
+    {
+        return any( transform( problems, new Function<ModelProblem, Severity>()
+        {
+            @Override
+            public Severity apply( ModelProblem input )
+            {
+                return input.getSeverity();
+            }
+        } ), in( of( ERROR, FATAL ) ) );
+    }
+
+    /**
+     * Class definition
+     */
+
+    private final boolean errors;
+
+    private final T value;
+
+    private final Iterable<? extends ModelProblem> problems;
+
+    private Result( boolean errors, T model, Iterable<? extends ModelProblem> problems )
+    {
+        this.errors = errors;
+        this.value = model;
+        this.problems = problems;
+    }
+
+    public Iterable<? extends ModelProblem> getProblems()
+    {
+        return problems;
+    }
+
+    public T get()
+    {
+        return value;
+    }
+
+    public boolean hasErrors()
+    {
+        return errors;
+    }
+
+    private static final Function<Result<?>, Iterable<? extends ModelProblem>> GET_PROBLEMS =
+        new Function<Result<?>, Iterable<? extends ModelProblem>>()
+        {
+            @Override
+            public Iterable<? extends ModelProblem> apply( Result<?> input )
+            {
+                return input.getProblems();
+            }
+        };
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java
----------------------------------------------------------------------
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java
index 733a276..bdb623a 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java
@@ -78,6 +78,22 @@ public class UnresolvableModelException
     }
 
     /**
+     * Creates a new exception with specified cause
+     *
+     * @param cause
+     * @param groupId
+     * @param artifactId
+     * @param version
+     */
+    public UnresolvableModelException( Throwable cause, String groupId, String artifactId, String version )
+    {
+        super( cause );
+        this.groupId = groupId;
+        this.artifactId = artifactId;
+        this.version = version;
+    }
+
+    /**
      * Gets the group id of the unresolvable model.
      *
      * @return The group id of the unresolvable model, can be empty but never {@code null}.

http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model-builder/src/main/java/org/apache/maven/model/resolution/WorkspaceModelResolver.java
----------------------------------------------------------------------
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/WorkspaceModelResolver.java b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/WorkspaceModelResolver.java
new file mode 100644
index 0000000..d12edea
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/WorkspaceModelResolver.java
@@ -0,0 +1,33 @@
+package org.apache.maven.model.resolution;
+
+/*
+ * 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.Model;
+
+public interface WorkspaceModelResolver
+{
+
+    Model resolveRawModel( String groupId, String artifactId, String versionConstraint )
+        throws UnresolvableModelException;
+
+    Model resolveEffectiveModel( String groupId, String artifactId, String versionConstraint )
+        throws UnresolvableModelException;
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/maven/blob/be3fb200/maven-model/src/main/mdo/maven.mdo
----------------------------------------------------------------------
diff --git a/maven-model/src/main/mdo/maven.mdo b/maven-model/src/main/mdo/maven.mdo
index 43bdb7e..2821ea6 100644
--- a/maven-model/src/main/mdo/maven.mdo
+++ b/maven-model/src/main/mdo/maven.mdo
@@ -1466,12 +1466,18 @@
           <version>4.0.0+</version>
           <code>
             <![CDATA[
+    private String managementKey;
+
     /**
      * @return the management key as <code>groupId:artifactId:type</code>
      */
     public String getManagementKey()
     {
-        return groupId + ":" + artifactId + ":" + type + ( classifier != null ? ":" + classifier : "" );
+        if ( managementKey == null )
+        {
+            managementKey = groupId + ":" + artifactId + ":" + type + ( classifier != null ? ":" + classifier : "" );
+        }
+        return managementKey;
     }
             ]]>
           </code>