This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/maven.git
commit 6aa86c55b411666c9fbef94213fc2dc54438aa80 Author: Guillaume Nodet <gno...@gmail.com> AuthorDate: Mon Feb 3 09:29:15 2025 +0100 [MNG-8540] Replace ModelCache with the new cache API --- .../project/DefaultMavenProjectBuilderTest.java | 8 - .../apache/maven/project/ProjectBuilderTest.java | 8 - .../api/services/model/ModelCacheFactory.java | 40 ----- .../maven/impl/model/DefaultModelBuilder.java | 171 +++++++++++++++++---- .../apache/maven/impl/model/DefaultModelCache.java | 162 ------------------- .../maven/impl/model/DefaultModelCacheFactory.java | 33 ---- 6 files changed, 145 insertions(+), 277 deletions(-) diff --git a/impl/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java b/impl/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java index 0f06cf8019..60994b8213 100644 --- a/impl/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java +++ b/impl/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java @@ -25,8 +25,6 @@ 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.impl.InternalSession; @@ -338,12 +336,6 @@ void rereadPom_mng7063() throws Exception { 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/impl/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java b/impl/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java index ef4eede284..9cdd456ad4 100644 --- a/impl/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java +++ b/impl/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java @@ -29,8 +29,6 @@ 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,12 +177,6 @@ void testReadModifiedPoms(@TempDir Path tempDir) throws Exception { 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/impl/maven-impl/src/main/java/org/apache/maven/api/services/model/ModelCacheFactory.java b/impl/maven-impl/src/main/java/org/apache/maven/api/services/model/ModelCacheFactory.java deleted file mode 100644 index 340121d21f..0000000000 --- a/impl/maven-impl/src/main/java/org/apache/maven/api/services/model/ModelCacheFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - * <p> - * 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. - * <p> - * 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. - * - * @since 4.0.0 - */ -@Experimental -public interface ModelCacheFactory { - - @Nonnull - ModelCache newInstance(); -} diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java index 2809c0b19c..445f33cfcd 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java @@ -51,9 +51,12 @@ import org.apache.maven.api.Constants; import org.apache.maven.api.RemoteRepository; import org.apache.maven.api.Session; -import org.apache.maven.api.SessionData; import org.apache.maven.api.Type; import org.apache.maven.api.VersionRange; +import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.annotations.Nullable; +import org.apache.maven.api.cache.CacheMetadata; +import org.apache.maven.api.cache.CacheRetention; import org.apache.maven.api.di.Inject; import org.apache.maven.api.di.Named; import org.apache.maven.api.di.Singleton; @@ -81,7 +84,9 @@ import org.apache.maven.api.services.ModelSource; import org.apache.maven.api.services.ProblemCollector; import org.apache.maven.api.services.RepositoryFactory; +import org.apache.maven.api.services.Request; import org.apache.maven.api.services.RequestTrace; +import org.apache.maven.api.services.Result; import org.apache.maven.api.services.Source; import org.apache.maven.api.services.Sources; import org.apache.maven.api.services.SuperPomProvider; @@ -89,8 +94,6 @@ 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.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; @@ -151,7 +154,6 @@ public class DefaultModelBuilder implements ModelBuilder { private final PluginConfigurationExpander pluginConfigurationExpander; private final ModelVersionParser versionParser; private final List<ModelTransformer> transformers; - private final ModelCacheFactory modelCacheFactory; private final ModelResolver modelResolver; private final Interpolator interpolator; private final PathTranslator pathTranslator; @@ -176,7 +178,6 @@ public DefaultModelBuilder( PluginConfigurationExpander pluginConfigurationExpander, ModelVersionParser versionParser, List<ModelTransformer> transformers, - ModelCacheFactory modelCacheFactory, ModelResolver modelResolver, Interpolator interpolator, PathTranslator pathTranslator, @@ -197,7 +198,6 @@ public DefaultModelBuilder( this.pluginConfigurationExpander = pluginConfigurationExpander; this.versionParser = versionParser; this.transformers = transformers; - this.modelCacheFactory = modelCacheFactory; this.modelResolver = modelResolver; this.interpolator = interpolator; this.pathTranslator = pathTranslator; @@ -253,7 +253,6 @@ protected class ModelBuilderSessionState implements ModelProblemCollector { final Session session; final ModelBuilderRequest request; final DefaultModelBuilderResult result; - final ModelCache cache; final Graph dag; final Map<GAKey, Set<ModelSource>> mappedSources; @@ -270,9 +269,6 @@ protected class ModelBuilderSessionState implements ModelProblemCollector { request.getSession(), request, new DefaultModelBuilderResult(request, ProblemCollector.create(request.getSession())), - request.getSession() - .getData() - .computeIfAbsent(SessionData.key(ModelCache.class), modelCacheFactory::newInstance), new Graph(), new ConcurrentHashMap<>(64), List.of(), @@ -292,7 +288,6 @@ private ModelBuilderSessionState( Session session, ModelBuilderRequest request, DefaultModelBuilderResult result, - ModelCache cache, Graph dag, Map<GAKey, Set<ModelSource>> mappedSources, List<RemoteRepository> pomRepositories, @@ -301,7 +296,6 @@ private ModelBuilderSessionState( this.session = session; this.request = request; this.result = result; - this.cache = cache; this.dag = dag; this.mappedSources = mappedSources; this.pomRepositories = pomRepositories; @@ -330,15 +324,7 @@ ModelBuilderSessionState derive(ModelBuilderRequest request, DefaultModelBuilder throw new IllegalArgumentException("Session mismatch"); } return new ModelBuilderSessionState( - session, - request, - result, - cache, - dag, - mappedSources, - pomRepositories, - externalRepositories, - repositories); + session, request, result, dag, mappedSources, pomRepositories, externalRepositories, repositories); } @Override @@ -346,8 +332,7 @@ public String toString() { return "ModelBuilderSession[" + "session=" + session + ", " + "request=" + request + ", " + "result=" - + result + ", " + "cache=" - + cache + ']'; + + result + ']'; } PhasingExecutor createExecutor() { @@ -707,7 +692,6 @@ private void loadFromRoot(Path root, Path top) { + "build, the top project will be used as the root project.", top, root); - cache.clear(); mappedSources.clear(); loadFromRoot(top, top); } @@ -1789,6 +1773,124 @@ ModelSource resolveReactorModel(String groupId, String artifactId, String versio return null; } + record RgavCacheKey( + Session session, + RequestTrace trace, + List<RemoteRepository> repositories, + String groupId, + String artifactId, + String version, + String classifier, + String tag) + implements Request<Session> { + @Nonnull + @Override + public Session getSession() { + return session; + } + + @Nullable + @Override + public RequestTrace getTrace() { + return trace; + } + + @Override + public boolean equals(Object o) { + return o instanceof RgavCacheKey that + && Objects.equals(tag, that.tag) + && Objects.equals(groupId, that.groupId) + && Objects.equals(version, that.version) + && Objects.equals(artifactId, that.artifactId) + && Objects.equals(classifier, that.classifier) + && Objects.equals(repositories, that.repositories); + } + + @Override + public int hashCode() { + return Objects.hash(repositories, groupId, artifactId, version, classifier, tag); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()).append("[").append("gav='"); + if (groupId != null) { + sb.append(groupId); + } + sb.append(":"); + if (artifactId != null) { + sb.append(artifactId); + } + sb.append(":"); + if (version != null) { + sb.append(version); + } + sb.append(":"); + if (classifier != null) { + sb.append(classifier); + } + sb.append("', tag='"); + sb.append(tag); + sb.append("']"); + return sb.toString(); + } + } + + record SourceCacheKey(Session session, RequestTrace trace, Source source, String tag) + implements Request<Session>, CacheMetadata { + @Nonnull + @Override + public Session getSession() { + return session; + } + + @Nullable + @Override + public RequestTrace getTrace() { + return trace; + } + + @Override + public CacheRetention getCacheRetention() { + return source instanceof CacheMetadata cacheMetadata ? cacheMetadata.getCacheRetention() : null; + } + + @Override + public boolean equals(Object o) { + return o instanceof SourceCacheKey that + && Objects.equals(tag, that.tag) + && Objects.equals(source, that.source); + } + + @Override + public int hashCode() { + return Objects.hash(source, tag); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + "location=" + source.getLocation() + ", tag=" + tag + + ", path=" + source.getPath() + ']'; + } + } + + static class SourceResponse<R extends Request<?>, T> implements Result<R> { + private final R request; + private final T response; + + SourceResponse(R request, T response) { + this.request = request; + this.response = response; + } + + @Nonnull + @Override + public R getRequest() { + return request; + } + } + private <T> T cache( List<RemoteRepository> repositories, String groupId, @@ -1797,11 +1899,28 @@ private <T> T cache( String classifier, String tag, Supplier<T> supplier) { - return cache.computeIfAbsent(repositories, groupId, artifactId, version, classifier, tag, supplier); + RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(session, request); + try { + RgavCacheKey r = new RgavCacheKey( + session, trace.mvnTrace(), repositories, groupId, artifactId, version, classifier, tag); + SourceResponse<RgavCacheKey, T> response = + InternalSession.from(session).request(r, tr -> new SourceResponse<>(tr, supplier.get())); + return response.response; + } finally { + RequestTraceHelper.exit(trace); + } } private <T> T cache(Source source, String tag, Supplier<T> supplier) throws ModelBuilderException { - return cache.computeIfAbsent(source, tag, supplier); + RequestTraceHelper.ResolverTrace trace = RequestTraceHelper.enter(session, request); + try { + SourceCacheKey r = new SourceCacheKey(session, trace.mvnTrace(), source, tag); + SourceResponse<SourceCacheKey, T> response = + InternalSession.from(session).request(r, tr -> new SourceResponse<>(tr, supplier.get())); + return response.response; + } finally { + RequestTraceHelper.exit(trace); + } } boolean isBuildRequest() { diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelCache.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelCache.java deleted file mode 100644 index 8c6cc1bb92..0000000000 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelCache.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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.impl.model; - -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.function.Supplier; - -import org.apache.maven.api.RemoteRepository; -import org.apache.maven.api.services.Source; -import org.apache.maven.api.services.model.ModelCache; - -import static java.util.Objects.requireNonNull; - -/** - * A model builder cache backed by the repository system cache. - * - */ -public class DefaultModelCache implements ModelCache { - - private final ConcurrentMap<Object, Supplier<?>> cache; - - public DefaultModelCache() { - this(new ConcurrentHashMap<>()); - } - - private DefaultModelCache(ConcurrentMap<Object, Supplier<?>> cache) { - this.cache = requireNonNull(cache); - } - - @Override - @SuppressWarnings({"unchecked"}) - public <T> T computeIfAbsent( - List<RemoteRepository> repositories, - String groupId, - String artifactId, - String version, - String classifier, - String tag, - Supplier<T> data) { - return (T) computeIfAbsent(new RgavCacheKey(repositories, groupId, artifactId, version, classifier, tag), data); - } - - @Override - @SuppressWarnings({"unchecked"}) - public <T> T computeIfAbsent(Source path, String tag, Supplier<T> data) { - 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(); - } - - record RgavCacheKey( - List<RemoteRepository> repositories, - String groupId, - String artifactId, - String version, - String classifier, - String tag) { - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(getClass().getSimpleName()).append("[").append("gav='"); - if (groupId != null) { - sb.append(groupId); - } - sb.append(":"); - if (artifactId != null) { - sb.append(artifactId); - } - sb.append(":"); - if (version != null) { - sb.append(version); - } - sb.append(":"); - if (classifier != null) { - sb.append(classifier); - } - sb.append("', tag='"); - sb.append(tag); - sb.append("']"); - return sb.toString(); - } - } - - record SourceCacheKey(Source source, String tag) { - - @Override - public String toString() { - return getClass().getSimpleName() + "[" + "location=" + source.getLocation() + ", tag=" + tag + ", path=" - + source.getPath() + ']'; - } - } - - static class CachingSupplier<T> implements Supplier<T> { - Supplier<T> supplier; - volatile Object value; - - CachingSupplier(Supplier<T> supplier) { - this.supplier = supplier; - } - - @Override - @SuppressWarnings({"unchecked", "checkstyle:InnerAssignment"}) - public T get() { - Object v; - if ((v = value) == null) { - synchronized (this) { - if ((v = value) == null) { - try { - v = value = supplier.get(); - supplier = null; - } catch (Exception e) { - v = value = new AltRes(e); - } - } - } - } - if (v instanceof AltRes altRes) { - uncheckedThrow(altRes.t); - } - return (T) v; - } - - static class AltRes { - final Throwable t; - - AltRes(Throwable t) { - this.t = t; - } - } - } - - @SuppressWarnings("unchecked") - static <T extends Throwable> void uncheckedThrow(Throwable t) throws T { - throw (T) t; // rely on vacuous cast - } -} diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelCacheFactory.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelCacheFactory.java deleted file mode 100644 index ad567d934d..0000000000 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelCacheFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.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(); - } -}