From 8d9f8da444ff90726e459dcf6779051bbfbe7deb Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 18 Sep 2024 13:42:07 +0200 Subject: [PATCH] [MNG-8239] Add missing ModelCacheFactory (#1728) --- .../api/services/ModelBuilderRequest.java | 19 -- .../apache/maven/api/services/PathSource.java | 2 +- .../maven/api/services/model}/ModelCache.java | 20 +- .../api/services/model/ModelCacheFactory.java | 41 ++++ .../impl/model/DefaultModelBuilder.java | 34 ++- .../DefaultModelCache.java | 30 +-- .../impl/model/DefaultModelCacheFactory.java | 33 +++ .../DefaultArtifactDescriptorReader.java | 1 - .../impl/resolver/DefaultModelResolver.java | 80 ++++--- .../standalone/RepositorySystemSupplier.java | 4 +- .../impl/DefaultConsumerPomBuilder.java | 22 +- .../maven/project/DefaultProjectBuilder.java | 210 +++++++++++------- .../DefaultMavenProjectBuilderTest.java | 9 + .../maven/project/ProjectBuilderTest.java | 8 + .../MavenRepositorySystemSupplier.java | 4 +- 15 files changed, 324 insertions(+), 193 deletions(-) rename {api/maven-api-core/src/main/java/org/apache/maven/api/services => maven-api-impl/src/main/java/org/apache/maven/api/services/model}/ModelCache.java (63%) create mode 100644 maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelCacheFactory.java rename maven-api-impl/src/main/java/org/apache/maven/internal/impl/{resolver => model}/DefaultModelCache.java (85%) create mode 100644 maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelCacheFactory.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java index 323ba6466b..a72dd73049 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java @@ -146,9 +146,6 @@ public interface ModelBuilderRequest { @Nonnull ModelRepositoryHolder getModelRepositoryHolder(); - @Nullable - ModelCache getModelCache(); - @Nullable Object getListener(); @@ -210,7 +207,6 @@ public interface ModelBuilderRequest { Map userProperties; ModelResolver modelResolver; ModelRepositoryHolder modelRepositoryHolder; - ModelCache modelCache; Object listener; ModelBuilderResult interimResult; ModelTransformerContextBuilder transformerContextBuilder; @@ -233,7 +229,6 @@ public interface ModelBuilderRequest { this.userProperties = request.getUserProperties(); this.modelResolver = request.getModelResolver(); this.modelRepositoryHolder = request.getModelRepositoryHolder(); - this.modelCache = request.getModelCache(); this.listener = request.getListener(); this.interimResult = request.getInterimResult(); this.transformerContextBuilder = request.getTransformerContextBuilder(); @@ -310,11 +305,6 @@ public interface ModelBuilderRequest { return this; } - public ModelBuilderRequestBuilder modelCache(ModelCache modelCache) { - this.modelCache = modelCache; - return this; - } - public ModelBuilderRequestBuilder listener(Object listener) { this.listener = listener; return this; @@ -352,7 +342,6 @@ public interface ModelBuilderRequest { userProperties, modelResolver, modelRepositoryHolder, - modelCache, listener, interimResult, transformerContextBuilder, @@ -373,7 +362,6 @@ public interface ModelBuilderRequest { private final Map userProperties; private final ModelResolver modelResolver; private final ModelRepositoryHolder modelRepositoryHolder; - private final ModelCache modelCache; private final Object listener; private final ModelBuilderResult interimResult; private final ModelTransformerContextBuilder transformerContextBuilder; @@ -395,7 +383,6 @@ public interface ModelBuilderRequest { Map userProperties, ModelResolver modelResolver, ModelRepositoryHolder modelRepositoryHolder, - ModelCache modelCache, Object listener, ModelBuilderResult interimResult, ModelTransformerContextBuilder transformerContextBuilder, @@ -415,7 +402,6 @@ public interface ModelBuilderRequest { this.userProperties = userProperties != null ? Map.copyOf(userProperties) : session.getUserProperties(); this.modelResolver = modelResolver; this.modelRepositoryHolder = modelRepositoryHolder; - this.modelCache = modelCache; this.listener = listener; this.interimResult = interimResult; this.transformerContextBuilder = transformerContextBuilder; @@ -487,11 +473,6 @@ public interface ModelBuilderRequest { return modelRepositoryHolder; } - @Override - public ModelCache getModelCache() { - return modelCache; - } - public Object getListener() { return listener; } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathSource.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathSource.java index c6bd252fd6..e7b39ac1be 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathSource.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathSource.java @@ -72,7 +72,7 @@ class PathSource implements ModelSource { @Override public boolean equals(Object o) { - return this == o || o instanceof PathSource ps && Objects.equals(path, ps.path); + return this == o || o.getClass() == getClass() && Objects.equals(path, ((PathSource) o).path); } @Override diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelCache.java b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelCache.java similarity index 63% rename from api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelCache.java rename to maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelCache.java index b928c3c8e4..bae427bebf 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelCache.java +++ b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelCache.java @@ -16,21 +16,33 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.maven.api.services; +package org.apache.maven.api.services.model; import java.util.function.Supplier; +import org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.ThreadSafe; +import org.apache.maven.api.services.Source; + /** * 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 - * identity of a model. The tag allows for further classification of the associated data on the sole discretion of the - * model builder. + * formed by a combination of group id, artifact id, version and tag, or by the pom path on the filesystem and tag. + * The tag allows for further classification of the associated data on the sole discretion of the model builder. + * The cache is expected to be valid through the lifetime of the session, so the model builder is not allowed to + * store data which may change during the session, especially effective models which may be different if the + * user properties or activate profiles change between two invocations of the model builder. + * The cache implementation is expected to be thread-safe. * + * @since 4.0.0 */ +@Experimental +@ThreadSafe public interface ModelCache { T computeIfAbsent(String groupId, String artifactId, String version, String tag, Supplier data); T computeIfAbsent(Source path, String tag, Supplier data); + + void clear(); } diff --git a/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelCacheFactory.java b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelCacheFactory.java new file mode 100644 index 0000000000..3c8c9be789 --- /dev/null +++ b/maven-api-impl/src/main/java/org/apache/maven/api/services/model/ModelCacheFactory.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.api.services.model; + +import org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Nonnull; + +/** + * Factory for creating model caches. + *

+ * The model cache is meant for exclusive consumption by the model builder and is opaque to the cache implementation. + * The cache is created once per session and is valid through the lifetime of the session. + *

+ * The cache implementation could be annotated with {@code SessionScoped} to be created once per session, but + * this would make tests more complicated to write as they would all need to enter the session scope. + * This is similar to the {@code CIFriendlyVersionModelTransformer}. + * + * @since 4.0.0 + */ +@Experimental +public interface ModelCacheFactory { + + @Nonnull + ModelCache newInstance(); +} diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java index fb83c160f8..dcb7e820f2 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java @@ -42,6 +42,7 @@ import java.util.function.UnaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.maven.api.SessionData; import org.apache.maven.api.Type; import org.apache.maven.api.VersionRange; import org.apache.maven.api.annotations.Nullable; @@ -67,7 +68,6 @@ import org.apache.maven.api.services.ModelBuilder; import org.apache.maven.api.services.ModelBuilderException; import org.apache.maven.api.services.ModelBuilderRequest; import org.apache.maven.api.services.ModelBuilderResult; -import org.apache.maven.api.services.ModelCache; import org.apache.maven.api.services.ModelProblem; import org.apache.maven.api.services.ModelProblemCollector; import org.apache.maven.api.services.ModelResolver; @@ -86,6 +86,8 @@ import org.apache.maven.api.services.model.InheritanceAssembler; import org.apache.maven.api.services.model.LifecycleBindingsInjector; import org.apache.maven.api.services.model.ModelBuildingEvent; import org.apache.maven.api.services.model.ModelBuildingListener; +import org.apache.maven.api.services.model.ModelCache; +import org.apache.maven.api.services.model.ModelCacheFactory; import org.apache.maven.api.services.model.ModelInterpolator; import org.apache.maven.api.services.model.ModelNormalizer; import org.apache.maven.api.services.model.ModelPathTranslator; @@ -101,7 +103,6 @@ import org.apache.maven.api.services.model.ProfileSelector; import org.apache.maven.api.services.model.WorkspaceModelResolver; import org.apache.maven.api.services.xml.XmlReaderException; import org.apache.maven.api.services.xml.XmlReaderRequest; -import org.apache.maven.internal.impl.resolver.DefaultModelCache; import org.apache.maven.internal.impl.resolver.DefaultModelRepositoryHolder; import org.apache.maven.internal.impl.resolver.DefaultModelResolver; import org.apache.maven.model.v4.MavenTransformer; @@ -145,6 +146,7 @@ public class DefaultModelBuilder implements ModelBuilder { private final ModelTransformer transformer; private final ModelVersionParser versionParser; private final List transformers; + private final ModelCacheFactory modelCacheFactory; @SuppressWarnings("checkstyle:ParameterNumber") @Inject @@ -167,7 +169,8 @@ public class DefaultModelBuilder implements ModelBuilder { ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator, ModelTransformer transformer, ModelVersionParser versionParser, - List transformers) { + List transformers, + ModelCacheFactory modelCacheFactory) { this.modelProcessor = modelProcessor; this.modelValidator = modelValidator; this.modelNormalizer = modelNormalizer; @@ -187,6 +190,7 @@ public class DefaultModelBuilder implements ModelBuilder { this.transformer = transformer; this.versionParser = versionParser; this.transformers = transformers; + this.modelCacheFactory = modelCacheFactory; } @Override @@ -206,9 +210,6 @@ public class DefaultModelBuilder implements ModelBuilder { private static ModelBuilderRequest fillRequestDefaults(ModelBuilderRequest request) { ModelBuilderRequest.ModelBuilderRequestBuilder builder = ModelBuilderRequest.builder(request); - if (request.getModelCache() == null) { - builder.modelCache(new DefaultModelCache()); - } if (request.getModelRepositoryHolder() == null) { builder.modelRepositoryHolder(new DefaultModelRepositoryHolder( request.getSession(), @@ -1465,7 +1466,6 @@ public class DefaultModelBuilder implements ModelBuilder { .userProperties(request.getUserProperties()) .source(importSource) .modelResolver(modelResolver) - .modelCache(request.getModelCache()) .modelRepositoryHolder( request.getModelRepositoryHolder().copy()) .twoPhaseBuilding(false) @@ -1486,21 +1486,11 @@ public class DefaultModelBuilder implements ModelBuilder { private static T cache( ModelCache cache, String groupId, String artifactId, String version, String tag, Callable supplier) { - Supplier s = asSupplier(supplier); - if (cache == null) { - return s.get(); - } else { - return cache.computeIfAbsent(groupId, artifactId, version, tag, s); - } + return cache.computeIfAbsent(groupId, artifactId, version, tag, asSupplier(supplier)); } private static T cache(ModelCache cache, Source source, String tag, Callable supplier) { - Supplier s = asSupplier(supplier); - if (cache == null) { - return s.get(); - } else { - return cache.computeIfAbsent(source, tag, s); - } + return cache.computeIfAbsent(source, tag, asSupplier(supplier)); } private static Supplier asSupplier(Callable supplier) { @@ -1557,8 +1547,10 @@ public class DefaultModelBuilder implements ModelBuilder { return modelProcessor; } - private static ModelCache getModelCache(ModelBuilderRequest request) { - return request.getModelCache(); + private ModelCache getModelCache(ModelBuilderRequest request) { + return request.getSession() + .getData() + .computeIfAbsent(SessionData.key(ModelCache.class), modelCacheFactory::newInstance); } private static ModelBuildingListener getModelBuildingListener(ModelBuilderRequest request) { diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelCache.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelCache.java similarity index 85% rename from maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelCache.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelCache.java index f21eaa8f26..9438c7415d 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelCache.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelCache.java @@ -16,17 +16,15 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.maven.internal.impl.resolver; +package org.apache.maven.internal.impl.model; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Supplier; -import org.apache.maven.api.services.ModelCache; import org.apache.maven.api.services.Source; -import org.eclipse.aether.RepositoryCache; -import org.eclipse.aether.RepositorySystemSession; +import org.apache.maven.api.services.model.ModelCache; import static java.util.Objects.requireNonNull; @@ -35,25 +33,6 @@ import static java.util.Objects.requireNonNull; * */ public class DefaultModelCache implements ModelCache { - private static final String KEY = DefaultModelCache.class.getName(); - - @SuppressWarnings("unchecked") - public static ModelCache newInstance(RepositorySystemSession session, boolean anew) { - ConcurrentHashMap> cache; - RepositoryCache repositoryCache = session != null ? session.getCache() : null; - if (repositoryCache == null) { - return new DefaultModelCache(new ConcurrentHashMap<>()); - } else { - if (anew) { - cache = new ConcurrentHashMap<>(); - repositoryCache.put(session, KEY, cache); - } else { - cache = (ConcurrentHashMap>) - repositoryCache.computeIfAbsent(session, KEY, ConcurrentHashMap::new); - } - return new DefaultModelCache(cache); - } - } private final ConcurrentMap> cache; @@ -77,6 +56,11 @@ public class DefaultModelCache implements ModelCache { return (T) computeIfAbsent(new SourceCacheKey(path, tag), data); } + @Override + public void clear() { + cache.clear(); + } + protected Object computeIfAbsent(Object key, Supplier data) { return cache.computeIfAbsent(key, k -> new CachingSupplier<>(data)).get(); } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelCacheFactory.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelCacheFactory.java new file mode 100644 index 0000000000..ed025d2ff4 --- /dev/null +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelCacheFactory.java @@ -0,0 +1,33 @@ +/* + * 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.internal.impl.model; + +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; +import org.apache.maven.api.services.model.ModelCache; +import org.apache.maven.api.services.model.ModelCacheFactory; + +@Named +@Singleton +public class DefaultModelCacheFactory implements ModelCacheFactory { + @Override + public ModelCache newInstance() { + return new DefaultModelCache(); + } +} diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java index 2498441804..3c16120b20 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultArtifactDescriptorReader.java @@ -218,7 +218,6 @@ public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader .userProperties(Map.of()) .modelResolver(modelResolver) .modelRepositoryHolder(modelRepositoryHolder) - .modelCache(DefaultModelCache.newInstance(session, false)) .repositories(repositories) .build(); diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java index 0a16b9696c..4b66104f3d 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java @@ -23,6 +23,7 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -86,32 +87,7 @@ public class DefaultModelResolver implements ModelResolver { session.createArtifactCoordinates(groupId, artifactId, newVersion, "pom"), repositories); Path path = resolved.getPath(); String location = groupId + ":" + artifactId + ":" + newVersion; - return new ModelSource() { - @Override - public ModelSource resolve(ModelLocator modelLocator, String relative) { - return null; - } - - @Override - public Path getPath() { - return null; - } - - @Override - public InputStream openStream() throws IOException { - return Files.newInputStream(path); - } - - @Override - public String getLocation() { - return location; - } - - @Override - public Source resolve(String relative) { - return null; - } - }; + return new ResolverModelSource(path, location); } catch (VersionRangeResolverException | ArtifactResolverException e) { throw new ModelResolverException( e.getMessage() + " (remote repositories: " @@ -124,4 +100,56 @@ public class DefaultModelResolver implements ModelResolver { e); } } + + private static class ResolverModelSource implements ModelSource { + private final Path path; + private final String location; + + ResolverModelSource(Path path, String location) { + this.path = path; + this.location = location; + } + + @Override + public ModelSource resolve(ModelLocator modelLocator, String relative) { + return null; + } + + @Override + public Path getPath() { + return null; + } + + @Override + public InputStream openStream() throws IOException { + return Files.newInputStream(path); + } + + @Override + public String getLocation() { + return location; + } + + @Override + public Source resolve(String relative) { + return null; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResolverModelSource that = (ResolverModelSource) o; + return Objects.equals(path, that.path) && Objects.equals(location, that.location); + } + + @Override + public int hashCode() { + return Objects.hash(path, location); + } + } } diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java index 5115153bef..558dea7f72 100644 --- a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/RepositorySystemSupplier.java @@ -37,6 +37,7 @@ import org.apache.maven.internal.impl.model.DefaultDependencyManagementImporter; import org.apache.maven.internal.impl.model.DefaultDependencyManagementInjector; import org.apache.maven.internal.impl.model.DefaultInheritanceAssembler; import org.apache.maven.internal.impl.model.DefaultModelBuilder; +import org.apache.maven.internal.impl.model.DefaultModelCacheFactory; import org.apache.maven.internal.impl.model.DefaultModelInterpolator; import org.apache.maven.internal.impl.model.DefaultModelNormalizer; import org.apache.maven.internal.impl.model.DefaultModelPathTranslator; @@ -1060,7 +1061,8 @@ public class RepositorySystemSupplier implements Supplier { new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), new DefaultRootLocator()), new BuildModelTransformer(), new DefaultModelVersionParser(getVersionScheme()), - List.of()); + List.of(), + new DefaultModelCacheFactory()); } private RepositorySystem repositorySystem; diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java index ad434baf8b..ab2463adc6 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java @@ -26,7 +26,6 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; import org.apache.maven.api.SessionData; @@ -49,6 +48,7 @@ import org.apache.maven.api.services.model.DependencyManagementImporter; import org.apache.maven.api.services.model.DependencyManagementInjector; import org.apache.maven.api.services.model.InheritanceAssembler; import org.apache.maven.api.services.model.LifecycleBindingsInjector; +import org.apache.maven.api.services.model.ModelCacheFactory; import org.apache.maven.api.services.model.ModelInterpolator; import org.apache.maven.api.services.model.ModelNormalizer; import org.apache.maven.api.services.model.ModelPathTranslator; @@ -65,7 +65,6 @@ import org.apache.maven.internal.impl.InternalSession; import org.apache.maven.internal.impl.model.DefaultModelBuilder; import org.apache.maven.internal.impl.model.DefaultProfileSelector; import org.apache.maven.internal.impl.model.ProfileActivationFilePathInterpolator; -import org.apache.maven.internal.impl.resolver.DefaultModelCache; import org.apache.maven.model.v4.MavenModelVersion; import org.apache.maven.project.MavenProject; import org.eclipse.aether.RepositorySystem; @@ -141,6 +140,9 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder { @Inject private List transformers; + @Inject + private ModelCacheFactory modelCacheFactory; + Logger logger = LoggerFactory.getLogger(getClass()); @Override @@ -197,7 +199,8 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder { profileActivationFilePathInterpolator, modelTransformer, versionParser, - transformers); + transformers, + modelCacheFactory); InternalSession iSession = InternalSession.from(session); ModelBuilderRequest.ModelBuilderRequestBuilder request = ModelBuilderRequest.builder(); request.projectBuild(true); @@ -209,19 +212,6 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder { request.transformerContextBuilder(modelBuilder.newTransformerContextBuilder()); request.systemProperties(session.getSystemProperties()); request.userProperties(session.getUserProperties()); - request.modelCache(DefaultModelCache.newInstance(session, false)); - if (session.getCache() != null) { - Map map = (Map) session.getCache().get(session, DefaultModelCache.class.getName()); - List paths = map.keySet().stream() - .map(Object::toString) - .filter(s -> s.startsWith("SourceCacheKey")) - .map(s -> s.substring("SourceCacheKey[location=".length(), s.indexOf(", tag"))) - .sorted() - .distinct() - .toList(); - logger.debug("ModelCache contains " + paths.size()); - paths.forEach(s -> logger.debug(" " + s)); - } return modelBuilder.build(request.build()); } diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index ba7ca435f5..d90f09a5a1 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -37,6 +37,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Properties; import java.util.Set; import java.util.concurrent.Callable; @@ -75,7 +76,6 @@ import org.apache.maven.api.services.ModelBuilder; import org.apache.maven.api.services.ModelBuilderException; import org.apache.maven.api.services.ModelBuilderRequest; import org.apache.maven.api.services.ModelBuilderResult; -import org.apache.maven.api.services.ModelCache; import org.apache.maven.api.services.ModelProblem; import org.apache.maven.api.services.ModelResolver; import org.apache.maven.api.services.ModelResolverException; @@ -91,7 +91,6 @@ import org.apache.maven.artifact.InvalidRepositoryException; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.bridge.MavenRepositorySystem; import org.apache.maven.internal.impl.InternalSession; -import org.apache.maven.internal.impl.resolver.DefaultModelCache; import org.apache.maven.internal.impl.resolver.DefaultModelRepositoryHolder; import org.apache.maven.model.building.DefaultModelProblem; import org.apache.maven.model.building.FileModelSource; @@ -181,56 +180,7 @@ public class DefaultProjectBuilder implements ProjectBuilder { if (modelSource instanceof FileModelSource fms) { return ModelSource.fromPath(fms.getPath()); } else { - return new ModelSource() { - @Override - public ModelSource resolve(ModelLocator modelLocator, String relative) { - if (modelSource instanceof ModelSource3 ms) { - return toSource(ms.getRelatedSource( - new org.apache.maven.model.locator.ModelLocator() { - @Override - public File locatePom(File projectDirectory) { - return null; - } - - @Override - public Path locatePom(Path projectDirectory) { - return null; - } - - @Override - public Path locateExistingPom(Path project) { - return modelLocator.locateExistingPom(project); - } - }, - relative)); - } - return null; - } - - @Override - public Path getPath() { - return null; - } - - @Override - public InputStream openStream() throws IOException { - return modelSource.getInputStream(); - } - - @Override - public String getLocation() { - return modelSource.getLocation(); - } - - @Override - public Source resolve(String relative) { - if (modelSource instanceof ModelSource2 ms) { - return toSource(ms.getRelatedSource(relative)); - } else { - return null; - } - } - }; + return new WrapModelSource(modelSource); } } @@ -301,6 +251,132 @@ public class DefaultProjectBuilder implements ProjectBuilder { } } + private static class StubModelSource implements ModelSource { + private final String xml; + private final Artifact artifact; + + StubModelSource(String xml, Artifact artifact) { + this.xml = xml; + this.artifact = artifact; + } + + @Override + public ModelSource resolve(ModelLocator modelLocator, String relative) { + return null; + } + + @Override + public Path getPath() { + return null; + } + + @Override + public InputStream openStream() throws IOException { + return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public String getLocation() { + return artifact.getId(); + } + + @Override + public Source resolve(String relative) { + return null; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + StubModelSource that = (StubModelSource) o; + return Objects.equals(xml, that.xml) && Objects.equals(artifact, that.artifact); + } + + @Override + public int hashCode() { + return Objects.hash(xml, artifact); + } + } + + private static class WrapModelSource implements ModelSource { + private final org.apache.maven.model.building.ModelSource modelSource; + + WrapModelSource(org.apache.maven.model.building.ModelSource modelSource) { + this.modelSource = modelSource; + } + + @Override + public ModelSource resolve(ModelLocator modelLocator, String relative) { + if (modelSource instanceof ModelSource3 ms) { + return toSource(ms.getRelatedSource( + new org.apache.maven.model.locator.ModelLocator() { + @Override + public File locatePom(File projectDirectory) { + return null; + } + + @Override + public Path locatePom(Path projectDirectory) { + return null; + } + + @Override + public Path locateExistingPom(Path project) { + return modelLocator.locateExistingPom(project); + } + }, + relative)); + } + return null; + } + + @Override + public Path getPath() { + return null; + } + + @Override + public InputStream openStream() throws IOException { + return modelSource.getInputStream(); + } + + @Override + public String getLocation() { + return modelSource.getLocation(); + } + + @Override + public Source resolve(String relative) { + if (modelSource instanceof ModelSource2 ms) { + return toSource(ms.getRelatedSource(relative)); + } else { + return null; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + WrapModelSource that = (WrapModelSource) o; + return Objects.equals(modelSource, that.modelSource); + } + + @Override + public int hashCode() { + return Objects.hashCode(modelSource); + } + } + class BuildSession implements AutoCloseable { private final ProjectBuildingRequest request; private final RepositorySystemSession session; @@ -309,7 +385,6 @@ public class DefaultProjectBuilder implements ProjectBuilder { private final ConcurrentMap parentCache; private final ModelTransformerContextBuilder transformerContextBuilder; private final ExecutorService executor; - private final ModelCache modelCache; private final ModelResolver modelResolver; private final Map ciFriendlyVersions = new ConcurrentHashMap<>(); @@ -328,7 +403,6 @@ public class DefaultProjectBuilder implements ProjectBuilder { this.transformerContextBuilder = null; } this.parentCache = new ConcurrentHashMap<>(); - this.modelCache = DefaultModelCache.newInstance(session, true); this.modelResolver = new ModelResolverWrapper() { @Override protected org.apache.maven.model.resolution.ModelResolver getResolver( @@ -1131,7 +1205,6 @@ public class DefaultProjectBuilder implements ProjectBuilder { .map(internalSession::getRemoteRepository) .toList()); modelBuildingRequest.modelRepositoryHolder(holder); - modelBuildingRequest.modelCache(modelCache); modelBuildingRequest.transformerContextBuilder(transformerContextBuilder); modelBuildingRequest.repositories(request.getRemoteRepositories().stream() .map(r -> internalSession.getRemoteRepository(RepositoryUtils.toRepo(r))) @@ -1204,32 +1277,9 @@ public class DefaultProjectBuilder implements ProjectBuilder { buffer.append("").append(artifact.getType()).append(""); buffer.append(""); - return new ModelSource() { - @Override - public ModelSource resolve(ModelLocator modelLocator, String relative) { - return null; - } + String xml = buffer.toString(); - @Override - public Path getPath() { - return null; - } - - @Override - public InputStream openStream() throws IOException { - return new ByteArrayInputStream(buffer.toString().getBytes(StandardCharsets.UTF_8)); - } - - @Override - public String getLocation() { - return artifact.getId(); - } - - @Override - public Source resolve(String relative) { - return null; - } - }; + return new StubModelSource(xml, artifact); } private static String inheritedGroupId(final ModelBuilderResult result, final int modelIndex) { diff --git a/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java index 116d8a88cd..98f8ba9254 100644 --- a/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java +++ b/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java @@ -25,8 +25,11 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.List; +import org.apache.maven.api.SessionData; +import org.apache.maven.api.services.model.ModelCache; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.internal.impl.InternalSession; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -329,6 +332,12 @@ class DefaultMavenProjectBuilderTest extends AbstractMavenProjectTestCase { projectBuilder.build(pom.toFile(), buildingRequest).getProject(); assertThat(project.getName(), is("aid")); // inherited from artifactId + // clear the cache + InternalSession.from(buildingRequest.getRepositorySession()) + .getData() + .get(SessionData.key(ModelCache.class)) + .clear(); + try (InputStream pomResource = DefaultMavenProjectBuilderTest.class.getResourceAsStream("/projects/reread/pom2.xml")) { Files.copy(pomResource, pom, StandardCopyOption.REPLACE_EXISTING); 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 435b00a65c..b798c39bdf 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 @@ -29,6 +29,8 @@ import java.util.Properties; import java.util.concurrent.atomic.AtomicInteger; import org.apache.maven.AbstractCoreMavenComponentTestCase; +import org.apache.maven.api.SessionData; +import org.apache.maven.api.services.model.ModelCache; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Dependency; import org.apache.maven.model.InputLocation; @@ -179,6 +181,12 @@ class ProjectBuilderTest extends AbstractCoreMavenComponentTestCase { File child = new File(tempDir.toFile(), "child/pom.xml"); // build project once projectBuilder.build(child, configuration); + // clear the cache + mavenSession + .getSession() + .getData() + .get(SessionData.key(ModelCache.class)) + .clear(); // modify parent File parent = new File(tempDir.toFile(), "pom.xml"); String parentContent = new String(Files.readAllBytes(parent.toPath()), StandardCharsets.UTF_8); diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java index 82baf4890a..50daaf95ff 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemSupplier.java @@ -37,6 +37,7 @@ import org.apache.maven.internal.impl.model.DefaultDependencyManagementImporter; import org.apache.maven.internal.impl.model.DefaultDependencyManagementInjector; import org.apache.maven.internal.impl.model.DefaultInheritanceAssembler; import org.apache.maven.internal.impl.model.DefaultModelBuilder; +import org.apache.maven.internal.impl.model.DefaultModelCacheFactory; import org.apache.maven.internal.impl.model.DefaultModelInterpolator; import org.apache.maven.internal.impl.model.DefaultModelNormalizer; import org.apache.maven.internal.impl.model.DefaultModelPathTranslator; @@ -1062,7 +1063,8 @@ public class MavenRepositorySystemSupplier implements Supplier new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), new DefaultRootLocator()), new BuildModelTransformer(), new DefaultModelVersionParser(getVersionScheme()), - List.of()); + List.of(), + new DefaultModelCacheFactory()); } private RepositorySystem repositorySystem;