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 f5492208ec..4649d124d2 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 @@ -424,11 +424,28 @@ public class DefaultModelBuilder if ( parent != null ) { - parentData = readParentLocally( childModel, request, problems ); + String groupId = parent.getGroupId(); + String artifactId = parent.getArtifactId(); + String version = parent.getVersion(); + + parentData = getCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW ); if ( parentData == null ) { - parentData = readParentExternally( childModel, request, problems ); + parentData = readParentLocally( childModel, request, problems ); + + if ( parentData == null ) + { + parentData = readParentExternally( childModel, request, problems ); + } + + putCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW, parentData ); + } + else + { + parentData = + new ModelData( ModelUtils.cloneModel( parentData.getModel() ), parentData.getGroupId(), + parentData.getArtifactId(), parentData.getVersion() ); } } else @@ -497,23 +514,27 @@ public class DefaultModelBuilder { Parent parent = childModel.getParent(); + String groupId = parent.getGroupId(); + String artifactId = parent.getArtifactId(); + String version = parent.getVersion(); + ModelResolver modelResolver = request.getModelResolver(); if ( modelResolver == null ) { throw new IllegalArgumentException( "no model resolver provided, cannot resolve parent POM " - + toId( parent ) + " for POM " + toSourceHint( childModel ) ); + + toId( groupId, artifactId, version ) + " for POM " + toSourceHint( childModel ) ); } ModelSource modelSource; try { - modelSource = modelResolver.resolveModel( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() ); + modelSource = modelResolver.resolveModel( groupId, artifactId, version ); } catch ( UnresolvableModelException e ) { - problems.add( new ModelProblem( "Non-resolvable parent POM " + toId( parent ) + " for POM " - + toSourceHint( childModel ) + ": " + e.getMessage(), ModelProblem.Severity.FATAL, + problems.add( new ModelProblem( "Non-resolvable parent POM " + toId( groupId, artifactId, version ) + + " for POM " + toSourceHint( childModel ) + ": " + e.getMessage(), ModelProblem.Severity.FATAL, toSourceHint( childModel ), e ) ); throw new ModelBuildingException( problems ); } @@ -557,60 +578,95 @@ public class DefaultModelBuilder it.remove(); - if ( modelResolver == null ) - { - throw new IllegalArgumentException( "no model resolver provided, cannot resolve import POM " - + toId( dependency ) + " for POM " + toSourceHint( model ) ); - } + String groupId = dependency.getGroupId(); + String artifactId = dependency.getArtifactId(); + String version = dependency.getVersion(); - ModelSource importSource; - try - { - importSource = - modelResolver.resolveModel( dependency.getGroupId(), dependency.getArtifactId(), - dependency.getVersion() ); - } - catch ( UnresolvableModelException e ) - { - problems.add( new ModelProblem( "Non-resolvable import POM " + toId( dependency ) + " for POM " - + toSourceHint( model ) + ": " + e.getMessage(), ModelProblem.Severity.ERROR, - toSourceHint( model ), e ) ); - continue; - } + Model importModel = + getCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.EFFECTIVE ); - if ( importRequest == null ) + if ( importModel == null ) { - importRequest = new DefaultModelBuildingRequest(); - importRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL ); + if ( modelResolver == null ) + { + throw new IllegalArgumentException( "no model resolver provided, cannot resolve import POM " + + toId( groupId, artifactId, version ) + " for POM " + toSourceHint( model ) ); + } + + ModelSource importSource; + try + { + importSource = modelResolver.resolveModel( groupId, artifactId, version ); + } + catch ( UnresolvableModelException e ) + { + problems.add( new ModelProblem( "Non-resolvable import POM " + toId( groupId, artifactId, version ) + + " for POM " + toSourceHint( model ) + ": " + e.getMessage(), ModelProblem.Severity.ERROR, + toSourceHint( model ), e ) ); + continue; + } + + if ( importRequest == null ) + { + importRequest = new DefaultModelBuildingRequest(); + importRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL ); + } + + importRequest.setModelSource( importSource ); + importRequest.setModelResolver( modelResolver.newCopy() ); + + ModelBuildingResult importResult; + try + { + importResult = build( importRequest ); + } + catch ( ModelBuildingException e ) + { + problems.addAll( e.getProblems() ); + continue; + } + + problems.addAll( importResult.getProblems() ); + + importModel = importResult.getEffectiveModel(); + + putCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.EFFECTIVE, importModel ); } - - importRequest.setModelSource( importSource ); - importRequest.setModelResolver( modelResolver.newCopy() ); - - ModelBuildingResult importResult; - try + else { - importResult = build( importRequest ); + importModel = ModelUtils.cloneModel( importModel ); } - catch ( ModelBuildingException e ) - { - problems.addAll( e.getProblems() ); - continue; - } - - problems.addAll( importResult.getProblems() ); if ( importModels == null ) { importModels = new ArrayList(); } - importModels.add( importResult.getEffectiveModel() ); + importModels.add( importModel ); } dependencyManagementImporter.importManagement( model, importModels, request ); } + private void putCache( ModelCache modelCache, String groupId, String artifactId, String version, + ModelCacheTag tag, T data ) + { + if ( modelCache != null ) + { + modelCache.put( groupId, artifactId, version, tag.getName(), data ); + } + } + + private T getCache( ModelCache modelCache, String groupId, String artifactId, String version, + ModelCacheTag tag ) + { + if ( modelCache != null ) + { + return tag.getType().cast( modelCache.get( groupId, artifactId, version, tag.getName() ) ); + } + return null; + } + private void fireBuildExtensionsAssembled( Model model, ModelBuildingRequest request, List problems ) throws ModelBuildingException { @@ -669,16 +725,6 @@ public class DefaultModelBuilder return toId( groupId, artifactId, version ); } - private String toId( Parent parent ) - { - return toId( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() ); - } - - private String toId( Dependency dependency ) - { - return toId( dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() ); - } - private String toId( String groupId, String artifactId, String version ) { StringBuilder buffer = new StringBuilder( 96 ); 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 9baea57691..506a832f65 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 @@ -61,6 +61,8 @@ public class DefaultModelBuildingRequest private List modelBuildingListeners; + private ModelCache modelCache; + public File getPomFile() { return pomFile; @@ -279,4 +281,16 @@ public class DefaultModelBuildingRequest return this; } + public ModelCache getModelCache() + { + return this.modelCache; + } + + public DefaultModelBuildingRequest setModelCache( ModelCache modelCache ) + { + this.modelCache = modelCache; + + return this; + } + } 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 d2e5acf478..bae37502dd 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 @@ -262,4 +262,20 @@ public interface ModelBuildingRequest */ ModelBuildingRequest setModelBuildingListeners( List modelBuildingListeners ); + /** + * Gets the model cache to use for reuse of previously built models. + * + * @return The model cache or {@code null} if not set. + */ + ModelCache getModelCache(); + + /** + * Sets the model cache to use for reuse of previously built models. This is an optional component that serves + * performance optimizations. + * + * @param modelCache The model cache to use, may be {@code null}. + * @return This request, never {@code null}. + */ + ModelBuildingRequest setModelCache( ModelCache modelCache ); + } diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCache.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCache.java new file mode 100644 index 0000000000..3bf4093f0a --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCache.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. + */ + +/** + * Caches auxiliary data used during model building like already processed raw/effective models. The data in the cache + * is meant for exclusive consumption by the model builder and is opaque to the cache implementation. The cache key is + * formed by a combination of group id, artifact id, version and tag. The first three components generally refer to the + * identify of a model. The tag allows for further classification of the associated data on the sole discretion of the + * model builder. + * + * @author Benjamin Bentmann + */ +public interface ModelCache +{ + + /** + * Puts the specified data into the cache. + * + * @param groupId The group id of the cache record, must not be {@code null}. + * @param artifactId The artifact id of the cache record, must not be {@code null}. + * @param version The version of the cache record, must not be {@code null}. + * @param tag The tag of the cache record, must not be {@code null}. + * @param data The data to store in the cache, must not be {@code null}. + */ + void put( String groupId, String artifactId, String version, String tag, Object data ); + + /** + * Gets the specified data from the cache. + * + * @param groupId The group id of the cache record, must not be {@code null}. + * @param artifactId The artifact id of the cache record, must not be {@code null}. + * @param version The version of the cache record, must not be {@code null}. + * @param tag The tag of the cache record, must not be {@code null}. + * @return The requested data or {@code null} if none was present in the cache. + */ + Object get( String groupId, String artifactId, String version, String tag ); + +} 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 new file mode 100644 index 0000000000..0385bc591a --- /dev/null +++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java @@ -0,0 +1,84 @@ +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 org.apache.maven.model.Model; + +/** + * Describes a tag used by the model builder to access a {@link ModelCache}. This interface simply aggregates a name and + * a class to provide some type safety when working with the otherwise untyped cache. + * + * @author Benjamin Bentmann + * @param The type of data associated with the tag. + */ +interface ModelCacheTag +{ + + /** + * Gets the name of the tag. + * + * @return The name of the tag, must not be {@code null}. + */ + String getName(); + + /** + * Gets the type of data associated with this tag. + * + * @return The type of data, must not be {@code null}. + */ + Class getType(); + + /** + * The tag used to denote raw model data. + */ + public static final ModelCacheTag RAW = new ModelCacheTag() + { + + public String getName() + { + return "raw"; + } + + public Class getType() + { + return ModelData.class; + } + + }; + + /** + * The tag used to denote an effective model. + */ + public static final ModelCacheTag EFFECTIVE = new ModelCacheTag() + { + + public String getName() + { + return "effective"; + } + + public Class getType() + { + return Model.class; + } + + }; + +}