cstamas commented on code in PR #1700:
URL: https://github.com/apache/maven/pull/1700#discussion_r1773710095


##########
maven-api-impl/src/main/java/org/apache/maven/internal/impl/model/DefaultModelBuilder.java:
##########
@@ -188,271 +196,1586 @@ public DefaultModelBuilder(
         this.lifecycleBindingsInjector = lifecycleBindingsInjector;
         this.pluginConfigurationExpander = pluginConfigurationExpander;
         this.profileActivationFilePathInterpolator = 
profileActivationFilePathInterpolator;
-        this.transformer = transformer;
         this.versionParser = versionParser;
         this.transformers = transformers;
         this.modelCacheFactory = modelCacheFactory;
+        this.modelResolver = modelResolver;
     }
 
-    @Override
-    public ModelTransformerContextBuilder newTransformerContextBuilder() {
-        return new DefaultModelTransformerContextBuilder(this);
+    public ModelBuilderSession newSession() {
+        return new ModelBuilderSession() {
+            DefaultModelBuilderSession mainSession;
+
+            @Override
+            public ModelBuilderResult build(ModelBuilderRequest request) 
throws ModelBuilderException {
+                if (request.getInterimResult() != null) {
+                    if (mainSession == null) {
+                        throw new IllegalStateException("ModelBuilderSession 
is not initialized");
+                    }
+                    DefaultModelBuilderResult result = 
asDefaultModelBuilderResult(request.getInterimResult());
+                    return mainSession.derive(request, result).build2(new 
LinkedHashSet<>());
+                } else {
+                    DefaultModelBuilderSession session;
+                    if (mainSession == null) {
+                        mainSession = new DefaultModelBuilderSession(request);
+                        session = mainSession;
+                    } else {
+                        session = mainSession.derive(request, new 
DefaultModelBuilderResult());
+                    }
+                    return session.build(new LinkedHashSet<>());
+                }
+            }
+        };
     }
 
-    @Override
-    public ModelBuilderResult build(ModelBuilderRequest request) throws 
ModelBuilderException {
-        request = fillRequestDefaults(request);
-        if (request.getInterimResult() != null) {
-            return build(request, request.getInterimResult(), new 
LinkedHashSet<>());
-        } else {
-            return build(request, new LinkedHashSet<>());
+    protected final class DefaultModelBuilderSession implements 
ModelProblemCollector {
+        final Session session;
+        final ModelBuilderRequest request;
+        final DefaultModelBuilderResult result;
+        final ModelCache cache;
+        final Graph dag;
+        final Map<GAKey, Set<ModelSource>> mappedSources;
+
+        String source;
+        Model sourceModel;
+        Model rootModel;
+
+        List<RemoteRepository> pomRepositories;
+        List<RemoteRepository> externalRepositories;
+        List<RemoteRepository> repositories;
+
+        DefaultModelBuilderSession(ModelBuilderRequest request) {
+            this(request, new DefaultModelBuilderResult());
         }
-    }
 
-    private static ModelBuilderRequest fillRequestDefaults(ModelBuilderRequest 
request) {
-        ModelBuilderRequest.ModelBuilderRequestBuilder builder = 
ModelBuilderRequest.builder(request);
-        if (request.getModelRepositoryHolder() == null) {
-            builder.modelRepositoryHolder(new DefaultModelRepositoryHolder(
-                    request.getSession(),
-                    
DefaultModelRepositoryHolder.RepositoryMerging.POM_DOMINANT,
-                    request.getSession().getRemoteRepositories()));
-        }
-        if (request.getModelResolver() == null) {
-            builder.modelResolver(new DefaultModelResolver());
-        }
-        return builder.build();
-    }
+        DefaultModelBuilderSession(ModelBuilderRequest request, 
DefaultModelBuilderResult result) {
+            this(request.getSession(), request, result);
+        }
+
+        DefaultModelBuilderSession(Session session, ModelBuilderRequest 
request, DefaultModelBuilderResult result) {
+            this(
+                    session,
+                    request,
+                    result,
+                    session.getData()
+                            
.computeIfAbsent(SessionData.key(ModelCache.class), 
modelCacheFactory::newInstance));
+        }
+
+        DefaultModelBuilderSession(
+                Session session, ModelBuilderRequest request, 
DefaultModelBuilderResult result, ModelCache cache) {
+            this(session, request, result, cache, new Graph(), new 
ConcurrentHashMap<>(64), null, null, null);
+        }
+
+        @SuppressWarnings("checkstyle:ParameterNumber")
+        private DefaultModelBuilderSession(
+                Session session,
+                ModelBuilderRequest request,
+                DefaultModelBuilderResult result,
+                ModelCache cache,
+                Graph dag,
+                Map<GAKey, Set<ModelSource>> mappedSources,
+                List<RemoteRepository> pomRepositories,
+                List<RemoteRepository> externalRepositories,
+                List<RemoteRepository> repositories) {
+            this.session = session;
+            this.request = request;
+            this.result = result;
+            this.cache = cache;
+            this.dag = dag;
+            this.mappedSources = mappedSources;
+            if (pomRepositories == null) {
+                this.pomRepositories = List.of();
+                this.externalRepositories = List.copyOf(
+                        request.getRepositories() != null
+                                ? request.getRepositories()
+                                : session.getRemoteRepositories());
+                this.repositories = this.externalRepositories;
+            } else {
+                this.pomRepositories = pomRepositories;
+                this.externalRepositories = externalRepositories;
+                this.repositories = repositories;
+            }
+        }
+
+        public DefaultModelBuilderSession derive(ModelSource source) {
+            return derive(source, result);
+        }
+
+        public DefaultModelBuilderSession derive(ModelSource source, 
DefaultModelBuilderResult result) {
+            return derive(ModelBuilderRequest.build(request, source), result);
+        }
+
+        public DefaultModelBuilderSession derive(ModelBuilderRequest request, 
DefaultModelBuilderResult result) {
+            if (session != request.getSession()) {
+                throw new IllegalArgumentException("Session mismatch");
+            }
+            return new DefaultModelBuilderSession(
+                    session,
+                    request,
+                    result,
+                    cache,
+                    dag,
+                    mappedSources,
+                    pomRepositories,
+                    externalRepositories,
+                    repositories);
+        }
+
+        public Session session() {
+            return session;
+        }
+
+        public ModelBuilderRequest request() {
+            return request;
+        }
+
+        public ModelBuilderResult result() {
+            return result;
+        }
+
+        public ModelCache cache() {
+            return cache;
+        }
+
+        @Override
+        public String toString() {
+            return "ModelBuilderSession[" + "session="
+                    + session + ", " + "request="
+                    + request + ", " + "result="
+                    + result + ", " + "cache="
+                    + cache + ']';
+        }
+
+        private int getParallelism() {
+            int parallelism = Runtime.getRuntime().availableProcessors() / 2 + 
1;
+            try {
+                String str = 
request.getUserProperties().get(Constants.MAVEN_PROJECT_BUILDER_PARALLELISM);
+                if (str != null) {
+                    parallelism = Integer.parseInt(str);
+                }
+            } catch (Exception e) {
+                // ignore
+            }
+            return Math.max(1, Math.min(parallelism, 
Runtime.getRuntime().availableProcessors()));
+        }
+
+        public Model getRawModel(Path from, String groupId, String artifactId) 
{
+            ModelSource source = getSource(groupId, artifactId);
+            if (source != null) {
+                if (!addEdge(from, source.getPath())) {
+                    return null;
+                }
+                try {
+                    return derive(source).readRawModel();
+                } catch (ModelBuilderException e) {
+                    // gathered with problem collector
+                }
+            }
+            return null;
+        }
+
+        public Model getRawModel(Path from, Path path) {
+            if (!Files.isRegularFile(path)) {
+                throw new IllegalArgumentException("Not a regular file: " + 
path);
+            }
+            if (!addEdge(from, path)) {
+                return null;
+            }
+            try {
+                return derive(ModelSource.fromPath(path)).readRawModel();
+            } catch (ModelBuilderException e) {
+                // gathered with problem collector
+            }
+            return null;
+        }
+
+        private boolean addEdge(Path from, Path p) {
+            try {
+                dag.addEdge(from.toString(), p.toString());
+                return true;
+            } catch (Graph.CycleDetectedException e) {
+                add(new DefaultModelProblem(
+                        "Cycle detected between models at " + from + " and " + 
p,
+                        Severity.FATAL,
+                        null,
+                        null,
+                        0,
+                        0,
+                        null,
+                        e));
+                return false;
+            }
+        }
+
+        public ModelSource getSource(String groupId, String artifactId) {
+            Set<ModelSource> sources;
+            if (groupId != null) {
+                sources = mappedSources.get(new GAKey(groupId, artifactId));
+                if (sources == null) {
+                    return null;
+                }
+            } else if (artifactId != null) {
+                sources = mappedSources.get(new GAKey(null, artifactId));
+                if (sources == null) {
+                    return null;
+                }
+            } else {
+                return null;
+            }
+            return sources.stream()
+                    .reduce((a, b) -> {
+                        throw new IllegalStateException(String.format(
+                                "No unique Source for %s:%s: %s and %s",
+                                groupId, artifactId, a.getLocation(), 
b.getLocation()));
+                    })
+                    .orElse(null);
+        }
+
+        public void putSource(String groupId, String artifactId, ModelSource 
source) {
+            mappedSources
+                    .computeIfAbsent(new GAKey(groupId, artifactId), k -> new 
HashSet<>())
+                    .add(source);
+            if (groupId != null) {
+                mappedSources
+                        .computeIfAbsent(new GAKey(null, artifactId), k -> new 
HashSet<>())
+                        .add(source);
+            }
+        }
+
+        public boolean hasFatalErrors() {
+            return result.getProblems().stream().anyMatch(p -> p.getSeverity() 
== ModelProblem.Severity.FATAL);
+        }
+
+        public boolean hasErrors() {
+            return result.getProblems().stream()
+                    .anyMatch(p -> p.getSeverity() == 
ModelProblem.Severity.FATAL
+                            || p.getSeverity() == ModelProblem.Severity.ERROR);
+        }
+
+        @Override
+        public List<ModelProblem> getProblems() {
+            return result.getProblems();
+        }
+
+        public void setSource(String source) {
+            this.source = source;
+            this.sourceModel = null;
+        }
+
+        public void setSource(Model source) {
+            this.sourceModel = source;
+            this.source = null;
+
+            if (rootModel == null) {
+                rootModel = source;
+            }
+        }
+
+        public String getSource() {
+            if (source == null && sourceModel != null) {
+                source = ModelProblemUtils.toPath(sourceModel);
+            }
+            return source;
+        }
+
+        private String getModelId() {
+            return ModelProblemUtils.toId(sourceModel);
+        }
+
+        public void setRootModel(Model rootModel) {
+            this.rootModel = rootModel;
+        }
+
+        public Model getRootModel() {
+            return rootModel;
+        }
+
+        public String getRootModelId() {
+            return ModelProblemUtils.toId(rootModel);
+        }
+
+        @Override
+        public void add(ModelProblem problem) {
+            result.getProblems().add(problem);
+        }
+
+        public void addAll(Collection<ModelProblem> problems) {
+            this.result.getProblems().addAll(problems);
+        }
+
+        @Override
+        public void add(BuilderProblem.Severity severity, ModelProblem.Version 
version, String message) {
+            add(severity, version, message, null, null);
+        }
+
+        @Override
+        public void add(
+                BuilderProblem.Severity severity,
+                ModelProblem.Version version,
+                String message,
+                InputLocation location) {
+            add(severity, version, message, location, null);
+        }
+
+        @Override
+        public void add(
+                BuilderProblem.Severity severity, ModelProblem.Version 
version, String message, Exception exception) {
+            add(severity, version, message, null, exception);
+        }
+
+        public void add(
+                BuilderProblem.Severity severity,
+                ModelProblem.Version version,
+                String message,
+                InputLocation location,
+                Exception exception) {
+            int line = -1;
+            int column = -1;
+            String source = null;
+            String modelId = null;
+
+            if (location != null) {
+                line = location.getLineNumber();
+                column = location.getColumnNumber();
+                if (location.getSource() != null) {
+                    modelId = location.getSource().getModelId();
+                    source = location.getSource().getLocation();
+                }
+            }
+
+            if (modelId == null) {
+                modelId = getModelId();
+                source = getSource();
+            }
+
+            if (line <= 0 && column <= 0 && exception instanceof 
ModelParserException e) {
+                line = e.getLineNumber();
+                column = e.getColumnNumber();
+            }
+
+            ModelProblem problem =
+                    new DefaultModelProblem(message, severity, version, 
source, line, column, modelId, exception);
+
+            add(problem);
+        }
+
+        public ModelBuilderException newModelBuilderException() {
+            ModelBuilderResult result = this.result;
+            if (result.getModelIds().isEmpty()) {
+                DefaultModelBuilderResult tmp = new 
DefaultModelBuilderResult();
+                tmp.setEffectiveModel(result.getEffectiveModel());
+                tmp.setProblems(getProblems());
+                
tmp.setActiveExternalProfiles(result.getActiveExternalProfiles());
+                String id = getRootModelId();
+                tmp.addModelId(id);
+                tmp.setRawModel(id, getRootModel());
+                result = tmp;
+            }
+            return new ModelBuilderException(result);
+        }
+
+        public List<RemoteRepository> getRepositories() {
+            return repositories;
+        }
+
+        /**
+         * TODO: this is not thread safe and the session is mutated
+         */
+        public void mergeRepositories(List<Repository> toAdd, boolean replace) 
{
+            List<RemoteRepository> repos =
+                    
toAdd.stream().map(session::createRemoteRepository).toList();
+            if (replace) {
+                Set<String> ids = 
repos.stream().map(RemoteRepository::getId).collect(Collectors.toSet());
+                repositories = repositories.stream()
+                        .filter(r -> !ids.contains(r.getId()))
+                        .toList();
+                pomRepositories = pomRepositories.stream()
+                        .filter(r -> !ids.contains(r.getId()))
+                        .toList();
+            } else {
+                Set<String> ids =
+                        
pomRepositories.stream().map(RemoteRepository::getId).collect(Collectors.toSet());
+                repos = repos.stream().filter(r -> 
!ids.contains(r.getId())).toList();
+            }
+
+            RepositoryFactory repositoryFactory = 
session.getService(RepositoryFactory.class);
+            if (request.getRepositoryMerging() == 
ModelBuilderRequest.RepositoryMerging.REQUEST_DOMINANT) {
+                repositories = repositoryFactory.aggregate(session, 
repositories, repos, true);
+                pomRepositories = repositories;
+            } else {
+                pomRepositories = repositoryFactory.aggregate(session, 
pomRepositories, repos, true);
+                repositories = repositoryFactory.aggregate(session, 
pomRepositories, externalRepositories, false);
+            }
+        }
+
+        //
+        // Transform raw model to build pom
+        //
+        Model transformRawToBuildPom(Model model) {
+            Model.Builder builder = Model.newBuilder(model);
+            builder = handleParent(model, builder);
+            builder = handleReactorDependencies(model, builder);
+            builder = handleCiFriendlyVersion(model, builder);
+            return builder.build();
+        }
+
+        //
+        // Infer parent information
+        //
+        Model.Builder handleParent(Model model, Model.Builder builder) {
+            Parent parent = model.getParent();
+            if (parent != null) {
+                String version = parent.getVersion();
+                String modVersion = replaceCiFriendlyVersion(version);
+                if (!Objects.equals(version, modVersion)) {
+                    if (builder == null) {
+                        builder = Model.newBuilder(model);
+                    }
+                    builder.parent(parent.withVersion(modVersion));
+                }
+            }
+            return builder;
+        }
+
+        //
+        // CI friendly versions
+        //
+        Model.Builder handleCiFriendlyVersion(Model model, Model.Builder 
builder) {
+            String version = model.getVersion();
+            String modVersion = replaceCiFriendlyVersion(version);
+            if (!Objects.equals(version, modVersion)) {
+                if (builder == null) {
+                    builder = Model.newBuilder(model);
+                }
+                builder.version(modVersion);
+            }
+            return builder;
+        }
+
+        //
+        // Infer inner reactor dependencies version
+        //
+        Model.Builder handleReactorDependencies(Model model, Model.Builder 
builder) {
+            List<Dependency> newDeps = new ArrayList<>();
+            boolean modified = false;
+            for (Dependency dep : model.getDependencies()) {
+                Dependency.Builder depBuilder = null;
+                if (dep.getVersion() == null) {
+                    Model depModel = getRawModel(model.getPomFile(), 
dep.getGroupId(), dep.getArtifactId());
+                    if (depModel != null) {
+                        String version = depModel.getVersion();
+                        InputLocation versionLocation = 
depModel.getLocation("version");
+                        if (version == null && depModel.getParent() != null) {
+                            version = depModel.getParent().getVersion();
+                            versionLocation = 
depModel.getParent().getLocation("version");
+                        }
+                        depBuilder = Dependency.newBuilder(dep);
+                        depBuilder.version(version).location("version", 
versionLocation);
+                        if (dep.getGroupId() == null) {
+                            String depGroupId = depModel.getGroupId();
+                            InputLocation groupIdLocation = 
depModel.getLocation("groupId");
+                            if (depGroupId == null && depModel.getParent() != 
null) {
+                                depGroupId = depModel.getParent().getGroupId();
+                                groupIdLocation = 
depModel.getParent().getLocation("groupId");
+                            }
+                            depBuilder.groupId(depGroupId).location("groupId", 
groupIdLocation);
+                        }
+                    }
+                }
+                if (depBuilder != null) {
+                    newDeps.add(depBuilder.build());
+                    modified = true;
+                } else {
+                    newDeps.add(dep);
+                }
+            }
+            if (modified) {
+                if (builder == null) {
+                    builder = Model.newBuilder(model);
+                }
+                builder.dependencies(newDeps);
+            }
+            return builder;
+        }
+
+        String replaceCiFriendlyVersion(String version) {
+            if (version != null) {
+                for (String key : Arrays.asList("changelist", "revision", 
"sha1")) {
+                    String val = request.getUserProperties().get(key);
+                    if (val != null) {
+                        version = version.replace("${" + key + "}", val);
+                    }
+                }
+            }
+            return version;
+        }
+
+        ModelBuilderResult build(Collection<String> importIds) throws 
ModelBuilderException {
+            if (request.getRequestType() == 
ModelBuilderRequest.RequestType.BUILD_POM) {
+                return buildBuildPom(importIds);
+            } else {
+                return buildParentOrDependency(importIds);
+            }
+        }
+
+        private ModelBuilderResult buildBuildPom(Collection<String> importIds) 
throws ModelBuilderException {
+            Path top = request.getSource().getPath();
+            if (top == null) {
+                throw new IllegalStateException("Recursive build requested but 
source has no path");
+            }
+            top = top.toAbsolutePath().normalize();
+
+            Path rootDirectory;
+            try {
+                rootDirectory = session.getRootDirectory();
+            } catch (IllegalStateException e) {
+                rootDirectory = 
session.getService(RootLocator.class).findRoot(top);
+            }
+            Path root = getModelProcessor().locateExistingPom(rootDirectory);
+            if (root != null) {
+                root = root.toAbsolutePath().normalize();
+            } else {
+                root = top;
+            }
+            loadFromRoot(root, top);
+            if (hasErrors()) {
+                throw newModelBuilderException();
+            }
+
+            build2(importIds);
+            for (DefaultModelBuilderResult r : result.getChildren()) {
+                if (r.getFileModel() == null) {
+                    continue;
+                }
+                var pbs = r.getProblems();
+                r.setProblems(List.of());
+                derive(ModelSource.fromPath(r.getFileModel().getPomFile()), 
r).build2(importIds);
+                r.getProblems().forEach(this::add);
+                pbs.addAll(r.getProblems());
+                r.setProblems(pbs);
+            }
+            if (hasErrors()) {
+                throw newModelBuilderException();
+            }
+
+            return result;
+        }
+
+        record PomToLoad(Path pom, Set<Path> parents) {}
+
+        @SuppressWarnings("checkstyle:MethodLength")
+        private void loadFromRoot(Path root, Path top) {
+            List<PomToLoad> toLoad = new ArrayList<>();
+            toLoad.add(new PomToLoad(root, Set.of()));
+            Set<Path> buildParts = new HashSet<>();
+            while (!toLoad.isEmpty()) {
+                PomToLoad pomToLoad = toLoad.remove(0);
+                Path pom = pomToLoad.pom;
+                Set<Path> parents = pomToLoad.parents;
+                DefaultModelBuilderResult r;
+                boolean isBuildPart = buildParts.contains(pom);
+                if (pom.equals(top)) {
+                    r = result;
+                } else {
+                    r = new DefaultModelBuilderResult();
+                    if (isBuildPart) {
+                        result.getChildren().add(r);
+                    }
+                }
+                try {
+                    Path pomDirectory = Files.isDirectory(pom) ? pom : 
pom.getParent();
+                    Model model = derive(ModelSource.fromPath(pom), 
r).readFileModel();
+                    r.setFileModel(model);
+                    Model activated = activateFileModel(model);
+                    r.setActivatedFileModel(activated);
+                    List<String> subprojects = activated.getSubprojects();
+                    if (subprojects.isEmpty()) {
+                        subprojects = activated.getModules();
+                    }
+                    for (String subproject : subprojects) {
+                        if (subproject == null || subproject.isEmpty()) {
+                            continue;
+                        }
+
+                        subproject =
+                                subproject.replace('\\', 
File.separatorChar).replace('/', File.separatorChar);
+
+                        Path subprojectFile = 
modelProcessor.locateExistingPom(pomDirectory.resolve(subproject));
+
+                        if (subprojectFile == null) {
+                            ModelProblem problem = new 
org.apache.maven.internal.impl.model.DefaultModelProblem(
+                                    "Child subproject " + subproject + " of " 
+ pomDirectory + " does not exist",
+                                    ModelProblem.Severity.ERROR,
+                                    ModelProblem.Version.BASE,
+                                    model,
+                                    -1,
+                                    -1,
+                                    null);
+                            r.getProblems().add(problem);
+                            add(problem);
+                            continue;
+                        }
+
+                        subprojectFile = 
subprojectFile.toAbsolutePath().normalize();
+
+                        if (parents.contains(subprojectFile)) {
+                            StringBuilder buffer = new StringBuilder(256);
+                            for (Path aggregatorFile : parents) {
+                                buffer.append(aggregatorFile).append(" -> ");
+                            }
+                            buffer.append(subprojectFile);
+
+                            ModelProblem problem = new 
org.apache.maven.internal.impl.model.DefaultModelProblem(
+                                    "Child subproject " + subprojectFile + " 
of " + pom + " forms aggregation cycle "
+                                            + buffer,
+                                    ModelProblem.Severity.ERROR,
+                                    ModelProblem.Version.BASE,
+                                    model,
+                                    -1,
+                                    -1,
+                                    null);
+                            r.getProblems().add(problem);
+                            continue;
+                        }
+
+                        toLoad.add(new PomToLoad(subprojectFile, 
concat(parents, pom)));
+                        if (pom.equals(top) && request.isRecursive()) {
+                            buildParts.add(subprojectFile);
+                        }
+                    }
+                } catch (ModelBuilderException e) {
+                    // gathered with problem collector
+                    add(Severity.ERROR, ModelProblem.Version.V40, "Failed to 
load project " + pom, e);
+                }
+                if (r != result) {
+                    result.getProblems().addAll(r.getProblems());
+                    r.getProblems().clear();
+                }
+            }
+            if (result.getFileModel() == null && !Objects.equals(top, root)) {
+                logger.warn(
+                        "The top project ({}) cannot be found in the reactor 
from root project ({}). "
+                                + "Make sure the root directory is correct (a 
missing '.mvn' directory in the root "
+                                + "project is the most common cause) and the 
project is correctly included "
+                                + "in the reactor (missing activated profiles, 
command line options, etc.). For this "
+                                + "build, the top project will be used as the 
root project.",
+                        top,
+                        root);
+                cache.clear();
+                mappedSources.clear();
+                loadFromRoot(top, top);
+            }
+        }
+
+        static <T> Set<T> concat(Set<T> a, T b) {
+            Set<T> result = new HashSet<>(a);
+            result.add(b);
+            return Set.copyOf(result);
+        }
+
+        private ModelBuilderResult buildParentOrDependency(Collection<String> 
importIds) throws ModelBuilderException {
+            // phase 1: read and validate raw model
+            Model fileModel = readFileModel();
+            result.setFileModel(fileModel);
+
+            Model activatedFileModel = activateFileModel(fileModel);
+            result.setActivatedFileModel(activatedFileModel);
+
+            // phase 2: build the effective model
+            return build2(importIds);
+        }
+
+        private ModelBuilderResult build2(Collection<String> importIds) throws 
ModelBuilderException {
+            // phase 2
+            Model resultModel = readEffectiveModel();
+            setSource(resultModel);
+            setRootModel(resultModel);
+
+            // model path translation
+            resultModel =
+                    modelPathTranslator.alignToBaseDirectory(resultModel, 
resultModel.getProjectDirectory(), request);
+
+            // plugin management injection
+            resultModel = 
pluginManagementInjector.injectManagement(resultModel, request, this);
+
+            resultModel = fireEvent(resultModel, request, this, 
ModelBuildingListener::buildExtensionsAssembled);
+
+            if (request.getRequestType() != 
ModelBuilderRequest.RequestType.DEPENDENCY) {
+                if (lifecycleBindingsInjector == null) {
+                    throw new IllegalStateException("lifecycle bindings 
injector is missing");
+                }
+
+                // lifecycle bindings injection
+                resultModel = 
lifecycleBindingsInjector.injectLifecycleBindings(resultModel, request, this);
+            }
+
+            // dependency management import
+            resultModel = importDependencyManagement(resultModel, importIds);
+
+            // dependency management injection
+            resultModel = 
dependencyManagementInjector.injectManagement(resultModel, request, this);
+
+            resultModel = modelNormalizer.injectDefaultValues(resultModel, 
request, this);
+
+            if (request.getRequestType() != 
ModelBuilderRequest.RequestType.DEPENDENCY) {
+                // plugins configuration
+                resultModel = 
pluginConfigurationExpander.expandPluginConfiguration(resultModel, request, 
this);
+            }
+
+            for (var transformer : transformers) {
+                resultModel = transformer.transformEffectiveModel(resultModel);
+            }
+
+            result.setEffectiveModel(resultModel);
+
+            // effective model validation
+            modelValidator.validateEffectiveModel(
+                    resultModel,
+                    request.getRequestType() == 
ModelBuilderRequest.RequestType.BUILD_POM
+                            ? ModelValidator.VALIDATION_LEVEL_STRICT
+                            : ModelValidator.VALIDATION_LEVEL_MINIMAL,
+                    request,
+                    this);
+
+            if (hasErrors()) {
+                throw newModelBuilderException();
+            }
+
+            return result;
+        }
+
+        ModelData readParent(Model childModel, ModelSource childSource) throws 
ModelBuilderException {
+            ModelData parentData = null;
+
+            Parent parent = childModel.getParent();
+            if (parent != null) {
+                parentData = readParentLocally(childModel, childSource);
+                if (parentData == null) {
+                    parentData = resolveAndReadParentExternally(childModel);
+                }
+
+                Model parentModel = parentData.model();
+                if (!"pom".equals(parentModel.getPackaging())) {
+                    add(
+                            Severity.ERROR,
+                            ModelProblem.Version.BASE,
+                            "Invalid packaging for parent POM " + 
ModelProblemUtils.toSourceHint(parentModel)
+                                    + ", must be \"pom\" but is \"" + 
parentModel.getPackaging() + "\"",
+                            parentModel.getLocation("packaging"));
+                }
+            }
+
+            return parentData;
+        }
+
+        private ModelData readParentLocally(Model childModel, ModelSource 
childSource) throws ModelBuilderException {
+            ModelSource candidateSource = getParentPomFile(childModel, 
childSource);
+            if (candidateSource == null) {
+                return null;
+            }
+            final Model candidateModel = 
derive(candidateSource).readRawModel();
+
+            //
+            // TODO jvz Why isn't all this checking the job of the duty of the 
workspace resolver, we know that we
+            // have a model that is suitable, yet more checks are done here 
and the one for the version is problematic
+            // before because with parents as ranges it will never work in 
this scenario.
+            //
+
+            String groupId = getGroupId(candidateModel);
+            String artifactId = candidateModel.getArtifactId();
+
+            Parent parent = childModel.getParent();
+            if (groupId == null
+                    || !groupId.equals(parent.getGroupId())
+                    || artifactId == null
+                    || !artifactId.equals(parent.getArtifactId())) {
+                StringBuilder buffer = new StringBuilder(256);
+                buffer.append("'parent.relativePath'");
+                if (childModel != getRootModel()) {
+                    buffer.append(" of POM 
").append(ModelProblemUtils.toSourceHint(childModel));
+                }
+                buffer.append(" points at 
").append(groupId).append(':').append(artifactId);
+                buffer.append(" instead of 
").append(parent.getGroupId()).append(':');
+                buffer.append(parent.getArtifactId()).append(", please verify 
your project structure");
+
+                setSource(childModel);
+                add(Severity.WARNING, ModelProblem.Version.BASE, 
buffer.toString(), parent.getLocation(""));
+                return null;
+            }
+
+            String version = getVersion(candidateModel);
+            if (version != null && parent.getVersion() != null && 
!version.equals(parent.getVersion())) {
+                try {
+                    VersionRange parentRange = 
versionParser.parseVersionRange(parent.getVersion());
+                    if 
(!parentRange.contains(versionParser.parseVersion(version))) {
+                        // version skew drop back to resolution from the 
repository
+                        return null;
+                    }
+
+                    // Validate versions aren't inherited when using parent 
ranges the same way as when read externally.
+                    String rawChildModelVersion = childModel.getVersion();
+
+                    if (rawChildModelVersion == null) {
+                        // Message below is checked for in the MNG-2199 core 
IT.
+                        add(
+                                Severity.FATAL,
+                                ModelProblem.Version.V31,
+                                "Version must be a constant",
+                                childModel.getLocation(""));
+
+                    } else {
+                        if 
(rawChildVersionReferencesParent(rawChildModelVersion)) {
+                            // Message below is checked for in the MNG-2199 
core IT.
+                            add(
+                                    Severity.FATAL,
+                                    ModelProblem.Version.V31,
+                                    "Version must be a constant",
+                                    childModel.getLocation("version"));
+                        }
+                    }
+
+                    // MNG-2199: What else to check here ?
+                } catch (VersionParserException e) {
+                    // invalid version range, so drop back to resolution from 
the repository
+                    return null;
+                }
+            }
+
+            //
+            // Here we just need to know that a version is fine to use but 
this validation we can do in our workspace
+            // resolver.
+            //
+
+            /*
+             * if ( version == null || !version.equals( parent.getVersion() ) 
) { return null; }
+             */

Review Comment:
   May be removed?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscr...@maven.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


Reply via email to