[MNG-8239] Add missing ModelCacheFactory (#1728)

This commit is contained in:
Guillaume Nodet 2024-09-18 13:42:07 +02:00 committed by GitHub
parent deb15be3b6
commit 8d9f8da444
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 324 additions and 193 deletions

View File

@ -146,9 +146,6 @@ public interface ModelBuilderRequest {
@Nonnull @Nonnull
ModelRepositoryHolder getModelRepositoryHolder(); ModelRepositoryHolder getModelRepositoryHolder();
@Nullable
ModelCache getModelCache();
@Nullable @Nullable
Object getListener(); Object getListener();
@ -210,7 +207,6 @@ public interface ModelBuilderRequest {
Map<String, String> userProperties; Map<String, String> userProperties;
ModelResolver modelResolver; ModelResolver modelResolver;
ModelRepositoryHolder modelRepositoryHolder; ModelRepositoryHolder modelRepositoryHolder;
ModelCache modelCache;
Object listener; Object listener;
ModelBuilderResult interimResult; ModelBuilderResult interimResult;
ModelTransformerContextBuilder transformerContextBuilder; ModelTransformerContextBuilder transformerContextBuilder;
@ -233,7 +229,6 @@ public interface ModelBuilderRequest {
this.userProperties = request.getUserProperties(); this.userProperties = request.getUserProperties();
this.modelResolver = request.getModelResolver(); this.modelResolver = request.getModelResolver();
this.modelRepositoryHolder = request.getModelRepositoryHolder(); this.modelRepositoryHolder = request.getModelRepositoryHolder();
this.modelCache = request.getModelCache();
this.listener = request.getListener(); this.listener = request.getListener();
this.interimResult = request.getInterimResult(); this.interimResult = request.getInterimResult();
this.transformerContextBuilder = request.getTransformerContextBuilder(); this.transformerContextBuilder = request.getTransformerContextBuilder();
@ -310,11 +305,6 @@ public interface ModelBuilderRequest {
return this; return this;
} }
public ModelBuilderRequestBuilder modelCache(ModelCache modelCache) {
this.modelCache = modelCache;
return this;
}
public ModelBuilderRequestBuilder listener(Object listener) { public ModelBuilderRequestBuilder listener(Object listener) {
this.listener = listener; this.listener = listener;
return this; return this;
@ -352,7 +342,6 @@ public interface ModelBuilderRequest {
userProperties, userProperties,
modelResolver, modelResolver,
modelRepositoryHolder, modelRepositoryHolder,
modelCache,
listener, listener,
interimResult, interimResult,
transformerContextBuilder, transformerContextBuilder,
@ -373,7 +362,6 @@ public interface ModelBuilderRequest {
private final Map<String, String> userProperties; private final Map<String, String> userProperties;
private final ModelResolver modelResolver; private final ModelResolver modelResolver;
private final ModelRepositoryHolder modelRepositoryHolder; private final ModelRepositoryHolder modelRepositoryHolder;
private final ModelCache modelCache;
private final Object listener; private final Object listener;
private final ModelBuilderResult interimResult; private final ModelBuilderResult interimResult;
private final ModelTransformerContextBuilder transformerContextBuilder; private final ModelTransformerContextBuilder transformerContextBuilder;
@ -395,7 +383,6 @@ public interface ModelBuilderRequest {
Map<String, String> userProperties, Map<String, String> userProperties,
ModelResolver modelResolver, ModelResolver modelResolver,
ModelRepositoryHolder modelRepositoryHolder, ModelRepositoryHolder modelRepositoryHolder,
ModelCache modelCache,
Object listener, Object listener,
ModelBuilderResult interimResult, ModelBuilderResult interimResult,
ModelTransformerContextBuilder transformerContextBuilder, ModelTransformerContextBuilder transformerContextBuilder,
@ -415,7 +402,6 @@ public interface ModelBuilderRequest {
this.userProperties = userProperties != null ? Map.copyOf(userProperties) : session.getUserProperties(); this.userProperties = userProperties != null ? Map.copyOf(userProperties) : session.getUserProperties();
this.modelResolver = modelResolver; this.modelResolver = modelResolver;
this.modelRepositoryHolder = modelRepositoryHolder; this.modelRepositoryHolder = modelRepositoryHolder;
this.modelCache = modelCache;
this.listener = listener; this.listener = listener;
this.interimResult = interimResult; this.interimResult = interimResult;
this.transformerContextBuilder = transformerContextBuilder; this.transformerContextBuilder = transformerContextBuilder;
@ -487,11 +473,6 @@ public interface ModelBuilderRequest {
return modelRepositoryHolder; return modelRepositoryHolder;
} }
@Override
public ModelCache getModelCache() {
return modelCache;
}
public Object getListener() { public Object getListener() {
return listener; return listener;
} }

View File

@ -72,7 +72,7 @@ class PathSource implements ModelSource {
@Override @Override
public boolean equals(Object o) { 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 @Override

View File

@ -16,21 +16,33 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.apache.maven.api.services; package org.apache.maven.api.services.model;
import java.util.function.Supplier; 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 * 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 * 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 * formed by a combination of group id, artifact id, version and tag, or by the pom path on the filesystem and tag.
* identity of a model. The tag allows for further classification of the associated data on the sole discretion of the * The tag allows for further classification of the associated data on the sole discretion of the model builder.
* 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 { public interface ModelCache {
<T> T computeIfAbsent(String groupId, String artifactId, String version, String tag, Supplier<T> data); <T> T computeIfAbsent(String groupId, String artifactId, String version, String tag, Supplier<T> data);
<T> T computeIfAbsent(Source path, String tag, Supplier<T> data); <T> T computeIfAbsent(Source path, String tag, Supplier<T> data);
void clear();
} }

View File

@ -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.
* <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.
* This is similar to the {@code CIFriendlyVersionModelTransformer}.
*
* @since 4.0.0
*/
@Experimental
public interface ModelCacheFactory {
@Nonnull
ModelCache newInstance();
}

View File

@ -42,6 +42,7 @@ import java.util.function.UnaryOperator;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.apache.maven.api.SessionData;
import org.apache.maven.api.Type; import org.apache.maven.api.Type;
import org.apache.maven.api.VersionRange; import org.apache.maven.api.VersionRange;
import org.apache.maven.api.annotations.Nullable; 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.ModelBuilderException;
import org.apache.maven.api.services.ModelBuilderRequest; import org.apache.maven.api.services.ModelBuilderRequest;
import org.apache.maven.api.services.ModelBuilderResult; 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.ModelProblem;
import org.apache.maven.api.services.ModelProblemCollector; import org.apache.maven.api.services.ModelProblemCollector;
import org.apache.maven.api.services.ModelResolver; 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.LifecycleBindingsInjector;
import org.apache.maven.api.services.model.ModelBuildingEvent; import org.apache.maven.api.services.model.ModelBuildingEvent;
import org.apache.maven.api.services.model.ModelBuildingListener; 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.ModelInterpolator;
import org.apache.maven.api.services.model.ModelNormalizer; import org.apache.maven.api.services.model.ModelNormalizer;
import org.apache.maven.api.services.model.ModelPathTranslator; 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.model.WorkspaceModelResolver;
import org.apache.maven.api.services.xml.XmlReaderException; import org.apache.maven.api.services.xml.XmlReaderException;
import org.apache.maven.api.services.xml.XmlReaderRequest; 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.DefaultModelRepositoryHolder;
import org.apache.maven.internal.impl.resolver.DefaultModelResolver; import org.apache.maven.internal.impl.resolver.DefaultModelResolver;
import org.apache.maven.model.v4.MavenTransformer; import org.apache.maven.model.v4.MavenTransformer;
@ -145,6 +146,7 @@ public class DefaultModelBuilder implements ModelBuilder {
private final ModelTransformer transformer; private final ModelTransformer transformer;
private final ModelVersionParser versionParser; private final ModelVersionParser versionParser;
private final List<org.apache.maven.api.spi.ModelTransformer> transformers; private final List<org.apache.maven.api.spi.ModelTransformer> transformers;
private final ModelCacheFactory modelCacheFactory;
@SuppressWarnings("checkstyle:ParameterNumber") @SuppressWarnings("checkstyle:ParameterNumber")
@Inject @Inject
@ -167,7 +169,8 @@ public class DefaultModelBuilder implements ModelBuilder {
ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator, ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator,
ModelTransformer transformer, ModelTransformer transformer,
ModelVersionParser versionParser, ModelVersionParser versionParser,
List<org.apache.maven.api.spi.ModelTransformer> transformers) { List<org.apache.maven.api.spi.ModelTransformer> transformers,
ModelCacheFactory modelCacheFactory) {
this.modelProcessor = modelProcessor; this.modelProcessor = modelProcessor;
this.modelValidator = modelValidator; this.modelValidator = modelValidator;
this.modelNormalizer = modelNormalizer; this.modelNormalizer = modelNormalizer;
@ -187,6 +190,7 @@ public class DefaultModelBuilder implements ModelBuilder {
this.transformer = transformer; this.transformer = transformer;
this.versionParser = versionParser; this.versionParser = versionParser;
this.transformers = transformers; this.transformers = transformers;
this.modelCacheFactory = modelCacheFactory;
} }
@Override @Override
@ -206,9 +210,6 @@ public class DefaultModelBuilder implements ModelBuilder {
private static ModelBuilderRequest fillRequestDefaults(ModelBuilderRequest request) { private static ModelBuilderRequest fillRequestDefaults(ModelBuilderRequest request) {
ModelBuilderRequest.ModelBuilderRequestBuilder builder = ModelBuilderRequest.builder(request); ModelBuilderRequest.ModelBuilderRequestBuilder builder = ModelBuilderRequest.builder(request);
if (request.getModelCache() == null) {
builder.modelCache(new DefaultModelCache());
}
if (request.getModelRepositoryHolder() == null) { if (request.getModelRepositoryHolder() == null) {
builder.modelRepositoryHolder(new DefaultModelRepositoryHolder( builder.modelRepositoryHolder(new DefaultModelRepositoryHolder(
request.getSession(), request.getSession(),
@ -1465,7 +1466,6 @@ public class DefaultModelBuilder implements ModelBuilder {
.userProperties(request.getUserProperties()) .userProperties(request.getUserProperties())
.source(importSource) .source(importSource)
.modelResolver(modelResolver) .modelResolver(modelResolver)
.modelCache(request.getModelCache())
.modelRepositoryHolder( .modelRepositoryHolder(
request.getModelRepositoryHolder().copy()) request.getModelRepositoryHolder().copy())
.twoPhaseBuilding(false) .twoPhaseBuilding(false)
@ -1486,21 +1486,11 @@ public class DefaultModelBuilder implements ModelBuilder {
private static <T> T cache( private static <T> T cache(
ModelCache cache, String groupId, String artifactId, String version, String tag, Callable<T> supplier) { ModelCache cache, String groupId, String artifactId, String version, String tag, Callable<T> supplier) {
Supplier<T> s = asSupplier(supplier); return cache.computeIfAbsent(groupId, artifactId, version, tag, asSupplier(supplier));
if (cache == null) {
return s.get();
} else {
return cache.computeIfAbsent(groupId, artifactId, version, tag, s);
}
} }
private static <T> T cache(ModelCache cache, Source source, String tag, Callable<T> supplier) { private static <T> T cache(ModelCache cache, Source source, String tag, Callable<T> supplier) {
Supplier<T> s = asSupplier(supplier); return cache.computeIfAbsent(source, tag, asSupplier(supplier));
if (cache == null) {
return s.get();
} else {
return cache.computeIfAbsent(source, tag, s);
}
} }
private static <T> Supplier<T> asSupplier(Callable<T> supplier) { private static <T> Supplier<T> asSupplier(Callable<T> supplier) {
@ -1557,8 +1547,10 @@ public class DefaultModelBuilder implements ModelBuilder {
return modelProcessor; return modelProcessor;
} }
private static ModelCache getModelCache(ModelBuilderRequest request) { private ModelCache getModelCache(ModelBuilderRequest request) {
return request.getModelCache(); return request.getSession()
.getData()
.computeIfAbsent(SessionData.key(ModelCache.class), modelCacheFactory::newInstance);
} }
private static ModelBuildingListener getModelBuildingListener(ModelBuilderRequest request) { private static ModelBuildingListener getModelBuildingListener(ModelBuilderRequest request) {

View File

@ -16,17 +16,15 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.apache.maven.internal.impl.resolver; package org.apache.maven.internal.impl.model;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.apache.maven.api.services.ModelCache;
import org.apache.maven.api.services.Source; import org.apache.maven.api.services.Source;
import org.eclipse.aether.RepositoryCache; import org.apache.maven.api.services.model.ModelCache;
import org.eclipse.aether.RepositorySystemSession;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
@ -35,25 +33,6 @@ import static java.util.Objects.requireNonNull;
* *
*/ */
public class DefaultModelCache implements ModelCache { public class DefaultModelCache implements ModelCache {
private static final String KEY = DefaultModelCache.class.getName();
@SuppressWarnings("unchecked")
public static ModelCache newInstance(RepositorySystemSession session, boolean anew) {
ConcurrentHashMap<Object, Supplier<?>> 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<Object, Supplier<?>>)
repositoryCache.computeIfAbsent(session, KEY, ConcurrentHashMap::new);
}
return new DefaultModelCache(cache);
}
}
private final ConcurrentMap<Object, Supplier<?>> cache; private final ConcurrentMap<Object, Supplier<?>> cache;
@ -77,6 +56,11 @@ public class DefaultModelCache implements ModelCache {
return (T) computeIfAbsent(new SourceCacheKey(path, tag), data); return (T) computeIfAbsent(new SourceCacheKey(path, tag), data);
} }
@Override
public void clear() {
cache.clear();
}
protected Object computeIfAbsent(Object key, Supplier<?> data) { protected Object computeIfAbsent(Object key, Supplier<?> data) {
return cache.computeIfAbsent(key, k -> new CachingSupplier<>(data)).get(); return cache.computeIfAbsent(key, k -> new CachingSupplier<>(data)).get();
} }

View File

@ -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();
}
}

View File

@ -218,7 +218,6 @@ public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader
.userProperties(Map.of()) .userProperties(Map.of())
.modelResolver(modelResolver) .modelResolver(modelResolver)
.modelRepositoryHolder(modelRepositoryHolder) .modelRepositoryHolder(modelRepositoryHolder)
.modelCache(DefaultModelCache.newInstance(session, false))
.repositories(repositories) .repositories(repositories)
.build(); .build();

View File

@ -23,6 +23,7 @@ import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -86,32 +87,7 @@ public class DefaultModelResolver implements ModelResolver {
session.createArtifactCoordinates(groupId, artifactId, newVersion, "pom"), repositories); session.createArtifactCoordinates(groupId, artifactId, newVersion, "pom"), repositories);
Path path = resolved.getPath(); Path path = resolved.getPath();
String location = groupId + ":" + artifactId + ":" + newVersion; String location = groupId + ":" + artifactId + ":" + newVersion;
return new ModelSource() { return new ResolverModelSource(path, 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;
}
};
} catch (VersionRangeResolverException | ArtifactResolverException e) { } catch (VersionRangeResolverException | ArtifactResolverException e) {
throw new ModelResolverException( throw new ModelResolverException(
e.getMessage() + " (remote repositories: " e.getMessage() + " (remote repositories: "
@ -124,4 +100,56 @@ public class DefaultModelResolver implements ModelResolver {
e); 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);
}
}
} }

View File

@ -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.DefaultDependencyManagementInjector;
import org.apache.maven.internal.impl.model.DefaultInheritanceAssembler; import org.apache.maven.internal.impl.model.DefaultInheritanceAssembler;
import org.apache.maven.internal.impl.model.DefaultModelBuilder; 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.DefaultModelInterpolator;
import org.apache.maven.internal.impl.model.DefaultModelNormalizer; import org.apache.maven.internal.impl.model.DefaultModelNormalizer;
import org.apache.maven.internal.impl.model.DefaultModelPathTranslator; import org.apache.maven.internal.impl.model.DefaultModelPathTranslator;
@ -1060,7 +1061,8 @@ public class RepositorySystemSupplier implements Supplier<RepositorySystem> {
new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), new DefaultRootLocator()), new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), new DefaultRootLocator()),
new BuildModelTransformer(), new BuildModelTransformer(),
new DefaultModelVersionParser(getVersionScheme()), new DefaultModelVersionParser(getVersionScheme()),
List.of()); List.of(),
new DefaultModelCacheFactory());
} }
private RepositorySystem repositorySystem; private RepositorySystem repositorySystem;

View File

@ -26,7 +26,6 @@ import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.maven.api.SessionData; 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.DependencyManagementInjector;
import org.apache.maven.api.services.model.InheritanceAssembler; import org.apache.maven.api.services.model.InheritanceAssembler;
import org.apache.maven.api.services.model.LifecycleBindingsInjector; 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.ModelInterpolator;
import org.apache.maven.api.services.model.ModelNormalizer; import org.apache.maven.api.services.model.ModelNormalizer;
import org.apache.maven.api.services.model.ModelPathTranslator; 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.DefaultModelBuilder;
import org.apache.maven.internal.impl.model.DefaultProfileSelector; import org.apache.maven.internal.impl.model.DefaultProfileSelector;
import org.apache.maven.internal.impl.model.ProfileActivationFilePathInterpolator; 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.model.v4.MavenModelVersion;
import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProject;
import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystem;
@ -141,6 +140,9 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
@Inject @Inject
private List<org.apache.maven.api.spi.ModelTransformer> transformers; private List<org.apache.maven.api.spi.ModelTransformer> transformers;
@Inject
private ModelCacheFactory modelCacheFactory;
Logger logger = LoggerFactory.getLogger(getClass()); Logger logger = LoggerFactory.getLogger(getClass());
@Override @Override
@ -197,7 +199,8 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
profileActivationFilePathInterpolator, profileActivationFilePathInterpolator,
modelTransformer, modelTransformer,
versionParser, versionParser,
transformers); transformers,
modelCacheFactory);
InternalSession iSession = InternalSession.from(session); InternalSession iSession = InternalSession.from(session);
ModelBuilderRequest.ModelBuilderRequestBuilder request = ModelBuilderRequest.builder(); ModelBuilderRequest.ModelBuilderRequestBuilder request = ModelBuilderRequest.builder();
request.projectBuild(true); request.projectBuild(true);
@ -209,19 +212,6 @@ class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
request.transformerContextBuilder(modelBuilder.newTransformerContextBuilder()); request.transformerContextBuilder(modelBuilder.newTransformerContextBuilder());
request.systemProperties(session.getSystemProperties()); request.systemProperties(session.getSystemProperties());
request.userProperties(session.getUserProperties()); 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<String> 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()); return modelBuilder.build(request.build());
} }

View File

@ -37,6 +37,7 @@ import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable; 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.ModelBuilderException;
import org.apache.maven.api.services.ModelBuilderRequest; import org.apache.maven.api.services.ModelBuilderRequest;
import org.apache.maven.api.services.ModelBuilderResult; 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.ModelProblem;
import org.apache.maven.api.services.ModelResolver; import org.apache.maven.api.services.ModelResolver;
import org.apache.maven.api.services.ModelResolverException; 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.artifact.repository.ArtifactRepository;
import org.apache.maven.bridge.MavenRepositorySystem; import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.internal.impl.InternalSession; 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.internal.impl.resolver.DefaultModelRepositoryHolder;
import org.apache.maven.model.building.DefaultModelProblem; import org.apache.maven.model.building.DefaultModelProblem;
import org.apache.maven.model.building.FileModelSource; import org.apache.maven.model.building.FileModelSource;
@ -181,56 +180,7 @@ public class DefaultProjectBuilder implements ProjectBuilder {
if (modelSource instanceof FileModelSource fms) { if (modelSource instanceof FileModelSource fms) {
return ModelSource.fromPath(fms.getPath()); return ModelSource.fromPath(fms.getPath());
} else { } else {
return new ModelSource() { return new WrapModelSource(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;
}
}
};
} }
} }
@ -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 { class BuildSession implements AutoCloseable {
private final ProjectBuildingRequest request; private final ProjectBuildingRequest request;
private final RepositorySystemSession session; private final RepositorySystemSession session;
@ -309,7 +385,6 @@ public class DefaultProjectBuilder implements ProjectBuilder {
private final ConcurrentMap<String, Object> parentCache; private final ConcurrentMap<String, Object> parentCache;
private final ModelTransformerContextBuilder transformerContextBuilder; private final ModelTransformerContextBuilder transformerContextBuilder;
private final ExecutorService executor; private final ExecutorService executor;
private final ModelCache modelCache;
private final ModelResolver modelResolver; private final ModelResolver modelResolver;
private final Map<String, String> ciFriendlyVersions = new ConcurrentHashMap<>(); private final Map<String, String> ciFriendlyVersions = new ConcurrentHashMap<>();
@ -328,7 +403,6 @@ public class DefaultProjectBuilder implements ProjectBuilder {
this.transformerContextBuilder = null; this.transformerContextBuilder = null;
} }
this.parentCache = new ConcurrentHashMap<>(); this.parentCache = new ConcurrentHashMap<>();
this.modelCache = DefaultModelCache.newInstance(session, true);
this.modelResolver = new ModelResolverWrapper() { this.modelResolver = new ModelResolverWrapper() {
@Override @Override
protected org.apache.maven.model.resolution.ModelResolver getResolver( protected org.apache.maven.model.resolution.ModelResolver getResolver(
@ -1131,7 +1205,6 @@ public class DefaultProjectBuilder implements ProjectBuilder {
.map(internalSession::getRemoteRepository) .map(internalSession::getRemoteRepository)
.toList()); .toList());
modelBuildingRequest.modelRepositoryHolder(holder); modelBuildingRequest.modelRepositoryHolder(holder);
modelBuildingRequest.modelCache(modelCache);
modelBuildingRequest.transformerContextBuilder(transformerContextBuilder); modelBuildingRequest.transformerContextBuilder(transformerContextBuilder);
modelBuildingRequest.repositories(request.getRemoteRepositories().stream() modelBuildingRequest.repositories(request.getRemoteRepositories().stream()
.map(r -> internalSession.getRemoteRepository(RepositoryUtils.toRepo(r))) .map(r -> internalSession.getRemoteRepository(RepositoryUtils.toRepo(r)))
@ -1204,32 +1277,9 @@ public class DefaultProjectBuilder implements ProjectBuilder {
buffer.append("<packaging>").append(artifact.getType()).append("</packaging>"); buffer.append("<packaging>").append(artifact.getType()).append("</packaging>");
buffer.append("</project>"); buffer.append("</project>");
return new ModelSource() { String xml = buffer.toString();
@Override
public ModelSource resolve(ModelLocator modelLocator, String relative) {
return null;
}
@Override return new StubModelSource(xml, artifact);
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;
}
};
} }
private static String inheritedGroupId(final ModelBuilderResult result, final int modelIndex) { private static String inheritedGroupId(final ModelBuilderResult result, final int modelIndex) {

View File

@ -25,8 +25,11 @@ import java.nio.file.Path;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.List; 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.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository; 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.BeforeEach;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -329,6 +332,12 @@ class DefaultMavenProjectBuilderTest extends AbstractMavenProjectTestCase {
projectBuilder.build(pom.toFile(), buildingRequest).getProject(); projectBuilder.build(pom.toFile(), buildingRequest).getProject();
assertThat(project.getName(), is("aid")); // inherited from artifactId 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 = try (InputStream pomResource =
DefaultMavenProjectBuilderTest.class.getResourceAsStream("/projects/reread/pom2.xml")) { DefaultMavenProjectBuilderTest.class.getResourceAsStream("/projects/reread/pom2.xml")) {
Files.copy(pomResource, pom, StandardCopyOption.REPLACE_EXISTING); Files.copy(pomResource, pom, StandardCopyOption.REPLACE_EXISTING);

View File

@ -29,6 +29,8 @@ import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.apache.maven.AbstractCoreMavenComponentTestCase; 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.execution.MavenSession;
import org.apache.maven.model.Dependency; import org.apache.maven.model.Dependency;
import org.apache.maven.model.InputLocation; import org.apache.maven.model.InputLocation;
@ -179,6 +181,12 @@ class ProjectBuilderTest extends AbstractCoreMavenComponentTestCase {
File child = new File(tempDir.toFile(), "child/pom.xml"); File child = new File(tempDir.toFile(), "child/pom.xml");
// build project once // build project once
projectBuilder.build(child, configuration); projectBuilder.build(child, configuration);
// clear the cache
mavenSession
.getSession()
.getData()
.get(SessionData.key(ModelCache.class))
.clear();
// modify parent // modify parent
File parent = new File(tempDir.toFile(), "pom.xml"); File parent = new File(tempDir.toFile(), "pom.xml");
String parentContent = new String(Files.readAllBytes(parent.toPath()), StandardCharsets.UTF_8); String parentContent = new String(Files.readAllBytes(parent.toPath()), StandardCharsets.UTF_8);

View File

@ -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.DefaultDependencyManagementInjector;
import org.apache.maven.internal.impl.model.DefaultInheritanceAssembler; import org.apache.maven.internal.impl.model.DefaultInheritanceAssembler;
import org.apache.maven.internal.impl.model.DefaultModelBuilder; 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.DefaultModelInterpolator;
import org.apache.maven.internal.impl.model.DefaultModelNormalizer; import org.apache.maven.internal.impl.model.DefaultModelNormalizer;
import org.apache.maven.internal.impl.model.DefaultModelPathTranslator; import org.apache.maven.internal.impl.model.DefaultModelPathTranslator;
@ -1062,7 +1063,8 @@ public class MavenRepositorySystemSupplier implements Supplier<RepositorySystem>
new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), new DefaultRootLocator()), new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), new DefaultRootLocator()),
new BuildModelTransformer(), new BuildModelTransformer(),
new DefaultModelVersionParser(getVersionScheme()), new DefaultModelVersionParser(getVersionScheme()),
List.of()); List.of(),
new DefaultModelCacheFactory());
} }
private RepositorySystem repositorySystem; private RepositorySystem repositorySystem;