From 9b58a3cfdccd4f7998f3f1d39a8687858248f76d Mon Sep 17 00:00:00 2001 From: Igor Fedorenko Date: Fri, 1 Mar 2013 09:19:22 -0500 Subject: [PATCH] MNG-5444 fixed building MavenProject from ModelSource To maintain compatibility with (the extremely unlikely) existing implementations of ModelSource, the new API methods are provided via optional ModelSource2 interface. Updated javadoc to encourage use of the new API. Signed-off-by: Igor Fedorenko --- .../apache/maven/project/ProjectBuilder.java | 3 + .../maven/project/ProjectBuilderTest.java | 16 ++++++ .../projects/modelsource/module01/pom.xml | 12 ++++ .../resources/projects/modelsource/pom.xml | 13 +++++ .../model/building/DefaultModelBuilder.java | 50 ++++++++--------- .../building/DefaultModelBuildingRequest.java | 6 +- .../maven/model/building/FileModelSource.java | 30 +++++++++- .../maven/model/building/ModelCacheTag.java | 2 +- .../maven/model/building/ModelData.java | 12 +++- .../maven/model/building/ModelSource.java | 4 ++ .../maven/model/building/ModelSource2.java | 56 +++++++++++++++++++ 11 files changed, 170 insertions(+), 34 deletions(-) create mode 100644 maven-core/src/test/resources/projects/modelsource/module01/pom.xml create mode 100644 maven-core/src/test/resources/projects/modelsource/pom.xml create mode 100644 maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource2.java diff --git a/maven-core/src/main/java/org/apache/maven/project/ProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/ProjectBuilder.java index 84e54a9fec..55adce7cb9 100644 --- a/maven-core/src/main/java/org/apache/maven/project/ProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/ProjectBuilder.java @@ -24,6 +24,7 @@ import java.util.List; import org.apache.maven.artifact.Artifact; import org.apache.maven.model.building.ModelSource; +import org.apache.maven.model.building.ModelSource2; /** * Builds in-memory descriptions of projects. @@ -74,6 +75,8 @@ public interface ProjectBuilder * @param request The project building request that holds further parameters, must not be {@code null}. * @return The result of the project building, never {@code null}. * @throws ProjectBuildingException If the project descriptor could not be successfully built. + * + * @see ModelSource2 */ ProjectBuildingResult build( ModelSource modelSource, ProjectBuildingRequest request ) throws ProjectBuildingException; diff --git a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java index d618d57c92..fc12b3e9d3 100644 --- a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java @@ -24,6 +24,8 @@ import java.util.Properties; import org.apache.maven.AbstractCoreMavenComponentTestCase; import org.apache.maven.execution.MavenSession; +import org.apache.maven.model.building.FileModelSource; +import org.apache.maven.model.building.ModelSource; public class ProjectBuilderTest extends AbstractCoreMavenComponentTestCase @@ -49,4 +51,18 @@ public class ProjectBuilderTest project.getCompileClasspathElements(); } + + public void testBuildFromModelSource() + throws Exception + { + File pomFile = new File( "src/test/resources/projects/modelsource/module01/pom.xml" ); + MavenSession mavenSession = createMavenSession( pomFile ); + ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest(); + configuration.setRepositorySession( mavenSession.getRepositorySession() ); + ModelSource modelSource = new FileModelSource( pomFile ); + ProjectBuildingResult result = + lookup( org.apache.maven.project.ProjectBuilder.class ).build( modelSource, configuration ); + + assertNotNull( result.getProject().getParentFile() ); + } } diff --git a/maven-core/src/test/resources/projects/modelsource/module01/pom.xml b/maven-core/src/test/resources/projects/modelsource/module01/pom.xml new file mode 100644 index 0000000000..cfaf9e8fa4 --- /dev/null +++ b/maven-core/src/test/resources/projects/modelsource/module01/pom.xml @@ -0,0 +1,12 @@ + + 4.0.0 + + + test.readparent + local-parent + 1.0 + + + module01 + diff --git a/maven-core/src/test/resources/projects/modelsource/pom.xml b/maven-core/src/test/resources/projects/modelsource/pom.xml new file mode 100644 index 0000000000..0fe29370e7 --- /dev/null +++ b/maven-core/src/test/resources/projects/modelsource/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + test.readparent + local-parent + pom + 1.0 + + + module + + + 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 25d9eab957..0d264cf09a 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 @@ -257,8 +257,8 @@ public class DefaultModelBuilder problems.setRootModel( inputModel ); - ModelData resultData = new ModelData( inputModel ); - ModelData superData = new ModelData( getSuperModel() ); + ModelData resultData = new ModelData( request.getModelSource(), inputModel ); + ModelData superData = new ModelData( null, getSuperModel() ); Collection parentIds = new LinkedHashSet(); parentIds.add( ModelProblemUtils.toId( inputModel ) ); @@ -304,7 +304,7 @@ public class DefaultModelBuilder configureResolver( request.getModelResolver(), tmpModel, problems ); - currentData = readParent( tmpModel, request, problems ); + currentData = readParent( tmpModel, currentData.getSource(), request, problems ); if ( currentData == null ) { @@ -644,7 +644,7 @@ public class DefaultModelBuilder return result; } - private ModelData readParent( Model childModel, ModelBuildingRequest request, + private ModelData readParent( Model childModel, ModelSource childSource, ModelBuildingRequest request, DefaultModelProblemCollector problems ) throws ModelBuildingException { @@ -662,7 +662,7 @@ public class DefaultModelBuilder if ( parentData == null ) { - parentData = readParentLocally( childModel, request, problems ); + parentData = readParentLocally( childModel, childSource, request, problems ); if ( parentData == null ) { @@ -683,9 +683,10 @@ public class DefaultModelBuilder File pomFile = parentData.getModel().getPomFile(); if ( pomFile != null ) { - File expectedParentFile = getParentPomFile( childModel ); + ModelSource expectedParentSource = getParentPomFile( childModel, childSource ); - if ( !pomFile.equals( expectedParentFile ) ) + if ( expectedParentSource instanceof ModelSource2 + && !pomFile.toURI().equals( ( (ModelSource2) expectedParentSource ).getLocationURI() ) ) { parentData = readParentExternally( childModel, request, problems ); } @@ -710,18 +711,24 @@ public class DefaultModelBuilder return parentData; } - private ModelData readParentLocally( Model childModel, ModelBuildingRequest request, + private ModelData readParentLocally( Model childModel, ModelSource childSource, ModelBuildingRequest request, DefaultModelProblemCollector problems ) throws ModelBuildingException { - File pomFile = getParentPomFile( childModel ); + ModelSource candidateSource = getParentPomFile( childModel, childSource ); - if ( pomFile == null || !pomFile.isFile() ) + if ( candidateSource == null ) { return null; } - Model candidateModel = readModel( null, pomFile, request, problems ); + File pomFile = null; + if ( candidateSource instanceof FileModelSource ) + { + pomFile = ( (FileModelSource) candidateSource ).getPomFile(); + } + + Model candidateModel = readModel( candidateSource, pomFile, request, problems ); String groupId = candidateModel.getGroupId(); if ( groupId == null && candidateModel.getParent() != null ) @@ -761,16 +768,14 @@ public class DefaultModelBuilder return null; } - ModelData parentData = new ModelData( candidateModel, groupId, artifactId, version ); + ModelData parentData = new ModelData( candidateSource, candidateModel, groupId, artifactId, version ); return parentData; } - private File getParentPomFile( Model childModel ) + private ModelSource getParentPomFile( Model childModel, ModelSource source ) { - File projectDirectory = childModel.getProjectDirectory(); - - if ( projectDirectory == null ) + if ( !( source instanceof ModelSource2 ) ) { return null; } @@ -782,16 +787,7 @@ public class DefaultModelBuilder return null; } - parentPath = parentPath.replace( '\\', File.separatorChar ).replace( '/', File.separatorChar ); - - File pomFile = new File( new File( projectDirectory, parentPath ).toURI().normalize() ); - - if ( pomFile.isDirectory() ) - { - pomFile = modelProcessor.locatePom( pomFile ); - } - - return pomFile; + return ( (ModelSource2) source ).getRelatedSource( parentPath ); } private ModelData readParentExternally( Model childModel, ModelBuildingRequest request, @@ -867,7 +863,7 @@ public class DefaultModelBuilder Model parentModel = readModel( modelSource, null, lenientRequest, problems ); - ModelData parentData = new ModelData( parentModel, groupId, artifactId, version ); + ModelData parentData = new ModelData( modelSource, parentModel, groupId, artifactId, version ); return parentData; } 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 4dff1c4f73..4719b88656 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 @@ -109,8 +109,12 @@ public class DefaultModelBuildingRequest return this; } - public ModelSource getModelSource() + public synchronized ModelSource getModelSource() { + if ( modelSource == null && pomFile != null ) + { + modelSource = new FileModelSource( pomFile ); + } return modelSource; } diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/FileModelSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/FileModelSource.java index f07e8508f5..12c7813d48 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/FileModelSource.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/FileModelSource.java @@ -23,6 +23,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.net.URI; /** * Wraps an ordinary {@link File} as a model source. @@ -30,10 +31,9 @@ import java.io.InputStream; * @author Benjamin Bentmann */ public class FileModelSource - implements ModelSource + implements ModelSource2 { - - private File pomFile; + private final File pomFile; /** * Creates a new model source backed by the specified file. @@ -76,4 +76,28 @@ public class FileModelSource return getLocation(); } + public ModelSource2 getRelatedSource( String relPath ) + { + relPath = relPath.replace( '\\', File.separatorChar ).replace( '/', File.separatorChar ); + + File relatedPom = new File( pomFile.getParentFile(), relPath ); + + if ( relatedPom.isDirectory() ) + { + // TODO figure out how to reuse ModelLocator.locatePom(File) here + relatedPom = new File( relatedPom, "pom.xml" ); + } + + if ( relatedPom.isFile() && relatedPom.canRead() ) + { + return new FileModelSource( new File( relatedPom.toURI().normalize() ) ); + } + + return null; + } + + public URI getLocationURI() + { + return pomFile.toURI(); + } } diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java index 90c64d6fc8..3967e3b133 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java @@ -83,7 +83,7 @@ interface ModelCacheTag public ModelData intoCache( ModelData data ) { Model model = ( data.getModel() != null ) ? data.getModel().clone() : null; - return new ModelData( model, data.getGroupId(), data.getArtifactId(), data.getVersion() ); + return new ModelData( data.getSource(), model, data.getGroupId(), data.getArtifactId(), data.getVersion() ); } public ModelData fromCache( ModelData data ) diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelData.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelData.java index 9a3ceaa9a6..e4c7527124 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelData.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelData.java @@ -32,6 +32,7 @@ import org.apache.maven.model.Profile; */ class ModelData { + private final ModelSource source; private Model model; @@ -50,8 +51,9 @@ class ModelData * * @param model The model to wrap, may be {@code null}. */ - public ModelData( Model model ) + public ModelData( ModelSource source, Model model ) { + this.source = source; this.model = model; } @@ -63,14 +65,20 @@ class ModelData * @param artifactId The effective artifact identifier of the model, may be {@code null}. * @param version The effective version of the model, may be {@code null}. */ - public ModelData( Model model, String groupId, String artifactId, String version ) + public ModelData( ModelSource source, Model model, String groupId, String artifactId, String version ) { + this.source = source; this.model = model; setGroupId( groupId ); setArtifactId( artifactId ); setVersion( version ); } + public ModelSource getSource() + { + return source; + } + /** * Gets the model being wrapped. * diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource.java index 5246d790bc..65ce7abbcc 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource.java @@ -24,8 +24,12 @@ import java.io.InputStream; /** * Provides access to the contents of a POM independently of the backing store (e.g. file system, database, memory). + *

+ * This interface does not support loading of parent POM(s) from the same backing store, integrators are strongly + * encouraged to implement {@link ModelSource2} instead of implementing this interface directly. * * @author Benjamin Bentmann + * @see ModelSource2 */ public interface ModelSource { diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource2.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource2.java new file mode 100644 index 0000000000..ea3872bfbc --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource2.java @@ -0,0 +1,56 @@ +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 java.net.URI; + +/** + * Provides access to the contents of a POM independently of the backing store (e.g. file system, database, memory). + *

+ * Unlike {@link ModelSource}, this interface supports loading of parent POM(s) from the same backing store and allows + * construction of MavenProject instances without the need to have parent POM(s) available from local or remote + * repositories. + *

+ * ModelSource2 instances are cached in {@link ModelBuildingRequest#getModelCache()}. Implementations must guarantee + * that the connection to the backing store remains active until request's {@link ModelCache} is discarded or flushed. + */ +public interface ModelSource2 + extends ModelSource +{ + /** + * Returns model source identified by a path relative to this model source POM. Implementation MUST + * be able to accept relPath parameter values that + *

    + *
  • use either / or \ file path separator
  • + *
  • have .. parent directory references
  • + *
  • point either at file or directory, in the latter case POM file name 'pom.xml' needs to be used by the + * requested model source.
  • + *
+ * + * @param relPath is the path of the requested model source relative to this model source POM. + * @return related model source or null if no such model source. + */ + ModelSource2 getRelatedSource( String relPath ); + + /** + * Returns location of the POM, never null. + */ + URI getLocationURI(); +}