View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.project;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.io.ByteArrayInputStream;
26  import java.io.File;
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.nio.charset.StandardCharsets;
30  import java.nio.file.Path;
31  import java.util.AbstractMap;
32  import java.util.ArrayList;
33  import java.util.Collections;
34  import java.util.HashMap;
35  import java.util.HashSet;
36  import java.util.LinkedHashSet;
37  import java.util.List;
38  import java.util.Map;
39  import java.util.Objects;
40  import java.util.Properties;
41  import java.util.Set;
42  import java.util.concurrent.ConcurrentHashMap;
43  import java.util.function.Supplier;
44  import java.util.stream.Collectors;
45  import java.util.stream.Stream;
46  
47  import org.apache.maven.ProjectCycleException;
48  import org.apache.maven.RepositoryUtils;
49  import org.apache.maven.api.SessionData;
50  import org.apache.maven.api.model.Build;
51  import org.apache.maven.api.model.Dependency;
52  import org.apache.maven.api.model.DependencyManagement;
53  import org.apache.maven.api.model.DeploymentRepository;
54  import org.apache.maven.api.model.Extension;
55  import org.apache.maven.api.model.Model;
56  import org.apache.maven.api.model.Plugin;
57  import org.apache.maven.api.model.Profile;
58  import org.apache.maven.api.model.ReportPlugin;
59  import org.apache.maven.api.services.BuilderProblem.Severity;
60  import org.apache.maven.api.services.ModelBuilder;
61  import org.apache.maven.api.services.ModelBuilderException;
62  import org.apache.maven.api.services.ModelBuilderRequest;
63  import org.apache.maven.api.services.ModelBuilderResult;
64  import org.apache.maven.api.services.ModelProblem;
65  import org.apache.maven.api.services.ModelProblem.Version;
66  import org.apache.maven.api.services.ModelProblemCollector;
67  import org.apache.maven.api.services.ModelSource;
68  import org.apache.maven.api.services.ModelTransformer;
69  import org.apache.maven.api.services.Source;
70  import org.apache.maven.api.services.model.LifecycleBindingsInjector;
71  import org.apache.maven.artifact.Artifact;
72  import org.apache.maven.artifact.InvalidRepositoryException;
73  import org.apache.maven.artifact.repository.ArtifactRepository;
74  import org.apache.maven.bridge.MavenRepositorySystem;
75  import org.apache.maven.internal.impl.InternalSession;
76  import org.apache.maven.internal.impl.resolver.ArtifactDescriptorUtils;
77  import org.apache.maven.model.building.DefaultModelProblem;
78  import org.apache.maven.model.building.FileModelSource;
79  import org.apache.maven.model.building.ModelBuildingRequest;
80  import org.apache.maven.model.building.ModelSource2;
81  import org.apache.maven.model.building.ModelSource3;
82  import org.apache.maven.model.root.RootLocator;
83  import org.apache.maven.plugin.PluginManagerException;
84  import org.apache.maven.plugin.PluginResolutionException;
85  import org.apache.maven.plugin.version.PluginVersionResolutionException;
86  import org.eclipse.aether.RepositorySystem;
87  import org.eclipse.aether.RepositorySystemSession;
88  import org.eclipse.aether.repository.LocalRepositoryManager;
89  import org.eclipse.aether.repository.WorkspaceRepository;
90  import org.eclipse.aether.resolution.ArtifactRequest;
91  import org.eclipse.aether.resolution.ArtifactResult;
92  import org.slf4j.Logger;
93  import org.slf4j.LoggerFactory;
94  
95  /**
96   * DefaultProjectBuilder
97   */
98  @Named
99  @Singleton
100 public class DefaultProjectBuilder implements ProjectBuilder {
101 
102     private final Logger logger = LoggerFactory.getLogger(getClass());
103     private final ModelBuilder modelBuilder;
104     private final ProjectBuildingHelper projectBuildingHelper;
105     private final MavenRepositorySystem repositorySystem;
106     private final org.eclipse.aether.RepositorySystem repoSystem;
107     private final ProjectDependenciesResolver dependencyResolver;
108     private final RootLocator rootLocator;
109     private final LifecycleBindingsInjector lifecycleBindingsInjector;
110 
111     @SuppressWarnings("checkstyle:ParameterNumber")
112     @Inject
113     public DefaultProjectBuilder(
114             ModelBuilder modelBuilder,
115             ProjectBuildingHelper projectBuildingHelper,
116             MavenRepositorySystem repositorySystem,
117             RepositorySystem repoSystem,
118             ProjectDependenciesResolver dependencyResolver,
119             RootLocator rootLocator,
120             LifecycleBindingsInjector lifecycleBindingsInjector) {
121         this.modelBuilder = modelBuilder;
122         this.projectBuildingHelper = projectBuildingHelper;
123         this.repositorySystem = repositorySystem;
124         this.repoSystem = repoSystem;
125         this.dependencyResolver = dependencyResolver;
126         this.rootLocator = rootLocator;
127         this.lifecycleBindingsInjector = lifecycleBindingsInjector;
128     }
129     // ----------------------------------------------------------------------
130     // MavenProjectBuilder Implementation
131     // ----------------------------------------------------------------------
132 
133     @Override
134     public ProjectBuildingResult build(File pomFile, ProjectBuildingRequest request) throws ProjectBuildingException {
135         try (BuildSession bs = new BuildSession(request)) {
136             Path path = pomFile.toPath();
137             return bs.build(path, ModelSource.fromPath(path));
138         }
139     }
140 
141     @Deprecated
142     @Override
143     public ProjectBuildingResult build(
144             org.apache.maven.model.building.ModelSource modelSource, ProjectBuildingRequest request)
145             throws ProjectBuildingException {
146         return build(toSource(modelSource), request);
147     }
148 
149     @Deprecated
150     static ModelSource toSource(org.apache.maven.model.building.ModelSource modelSource) {
151         if (modelSource instanceof FileModelSource fms) {
152             return ModelSource.fromPath(fms.getPath());
153         } else {
154             return new WrapModelSource(modelSource);
155         }
156     }
157 
158     @Override
159     public ProjectBuildingResult build(ModelSource modelSource, ProjectBuildingRequest request)
160             throws ProjectBuildingException {
161         try (BuildSession bs = new BuildSession(request)) {
162             return bs.build(null, modelSource);
163         }
164     }
165 
166     @Override
167     public ProjectBuildingResult build(Artifact artifact, ProjectBuildingRequest request)
168             throws ProjectBuildingException {
169         return build(artifact, false, request);
170     }
171 
172     @Override
173     public ProjectBuildingResult build(Artifact artifact, boolean allowStubModel, ProjectBuildingRequest request)
174             throws ProjectBuildingException {
175         try (BuildSession bs = new BuildSession(request)) {
176             return bs.build(artifact, allowStubModel);
177         }
178     }
179 
180     @Override
181     public List<ProjectBuildingResult> build(List<File> pomFiles, boolean recursive, ProjectBuildingRequest request)
182             throws ProjectBuildingException {
183         try (BuildSession bs = new BuildSession(request)) {
184             return bs.build(pomFiles, recursive);
185         }
186     }
187 
188     private static class StubModelSource implements ModelSource {
189         private final String xml;
190         private final Artifact artifact;
191 
192         StubModelSource(String xml, Artifact artifact) {
193             this.xml = xml;
194             this.artifact = artifact;
195         }
196 
197         @Override
198         public ModelSource resolve(ModelLocator modelLocator, String relative) {
199             return null;
200         }
201 
202         @Override
203         public Path getPath() {
204             return null;
205         }
206 
207         @Override
208         public InputStream openStream() throws IOException {
209             return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
210         }
211 
212         @Override
213         public String getLocation() {
214             return artifact.getId();
215         }
216 
217         @Override
218         public Source resolve(String relative) {
219             return null;
220         }
221 
222         @Override
223         public boolean equals(Object o) {
224             if (this == o) {
225                 return true;
226             }
227             if (o == null || getClass() != o.getClass()) {
228                 return false;
229             }
230             StubModelSource that = (StubModelSource) o;
231             return Objects.equals(xml, that.xml) && Objects.equals(artifact, that.artifact);
232         }
233 
234         @Override
235         public int hashCode() {
236             return Objects.hash(xml, artifact);
237         }
238     }
239 
240     private static class WrapModelSource implements ModelSource {
241         private final org.apache.maven.model.building.ModelSource modelSource;
242 
243         WrapModelSource(org.apache.maven.model.building.ModelSource modelSource) {
244             this.modelSource = modelSource;
245         }
246 
247         @Override
248         public ModelSource resolve(ModelLocator modelLocator, String relative) {
249             if (modelSource instanceof ModelSource3 ms) {
250                 return toSource(ms.getRelatedSource(
251                         new org.apache.maven.model.locator.ModelLocator() {
252                             @Override
253                             public File locatePom(File projectDirectory) {
254                                 return null;
255                             }
256 
257                             @Override
258                             public Path locatePom(Path projectDirectory) {
259                                 return null;
260                             }
261 
262                             @Override
263                             public Path locateExistingPom(Path project) {
264                                 return modelLocator.locateExistingPom(project);
265                             }
266                         },
267                         relative));
268             }
269             return null;
270         }
271 
272         @Override
273         public Path getPath() {
274             return null;
275         }
276 
277         @Override
278         public InputStream openStream() throws IOException {
279             return modelSource.getInputStream();
280         }
281 
282         @Override
283         public String getLocation() {
284             return modelSource.getLocation();
285         }
286 
287         @Override
288         public Source resolve(String relative) {
289             if (modelSource instanceof ModelSource2 ms) {
290                 return toSource(ms.getRelatedSource(relative));
291             } else {
292                 return null;
293             }
294         }
295 
296         @Override
297         public boolean equals(Object o) {
298             if (this == o) {
299                 return true;
300             }
301             if (o == null || getClass() != o.getClass()) {
302                 return false;
303             }
304             WrapModelSource that = (WrapModelSource) o;
305             return Objects.equals(modelSource, that.modelSource);
306         }
307 
308         @Override
309         public int hashCode() {
310             return Objects.hashCode(modelSource);
311         }
312     }
313 
314     class BuildSession implements AutoCloseable {
315         private final ProjectBuildingRequest request;
316         private final RepositorySystemSession session;
317         private final ModelBuilder.ModelBuilderSession modelBuilderSession;
318         private final Map<String, MavenProject> projectIndex = new ConcurrentHashMap<>(256);
319 
320         BuildSession(ProjectBuildingRequest request) {
321             this.request = request;
322             this.session =
323                     RepositoryUtils.overlay(request.getLocalRepository(), request.getRepositorySession(), repoSystem);
324             InternalSession iSession = InternalSession.from(session);
325             this.modelBuilderSession = modelBuilder.newSession();
326             // Save the ModelBuilderSession for later retrieval by the DefaultConsumerPomBuilder.
327             // Use replace(key, null, value) to make sure the *main* session, i.e. the one used
328             // to load the projects, is stored. This is to avoid the session being overwritten
329             // if a plugin uses the ProjectBuilder.
330             iSession.getData()
331                     .replace(SessionData.key(ModelBuilder.ModelBuilderSession.class), null, modelBuilderSession);
332         }
333 
334         @Override
335         public void close() {}
336 
337         ProjectBuildingResult build(Path pomFile, ModelSource modelSource) throws ProjectBuildingException {
338             ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
339 
340             try {
341                 MavenProject project = request.getProject();
342 
343                 List<ModelProblem> modelProblems = null;
344                 Throwable error = null;
345 
346                 if (project == null) {
347                     project = new MavenProject();
348                     project.setFile(pomFile != null ? pomFile.toFile() : null);
349 
350                     ModelBuilderRequest.ModelBuilderRequestBuilder builder = getModelBuildingRequest();
351                     ModelBuilderRequest.RequestType type = pomFile != null
352                                     && this.request.isProcessPlugins()
353                                     && this.request.getValidationLevel() == ModelBuildingRequest.VALIDATION_LEVEL_STRICT
354                             ? ModelBuilderRequest.RequestType.BUILD_EFFECTIVE
355                             : ModelBuilderRequest.RequestType.CONSUMER_PARENT;
356                     MavenProject theProject = project;
357                     ModelBuilderRequest request = builder.source(modelSource)
358                             .requestType(type)
359                             .locationTracking(true)
360                             .lifecycleBindingsInjector(
361                                     (m, r, p) -> injectLifecycleBindings(m, r, p, theProject, this.request))
362                             .build();
363 
364                     if (pomFile != null) {
365                         project.setRootDirectory(rootLocator.findRoot(pomFile.getParent()));
366                     }
367 
368                     ModelBuilderResult result;
369                     try {
370                         result = modelBuilderSession.build(request);
371                     } catch (ModelBuilderException e) {
372                         result = e.getResult();
373                         if (result == null || result.getEffectiveModel() == null) {
374                             throw new ProjectBuildingException(
375                                     e.getModelId(), e.getMessage(), pomFile != null ? pomFile.toFile() : null, e);
376                         }
377                         // validation error, continue project building and delay failing to help IDEs
378                         error = e;
379                     }
380 
381                     modelProblems = result.getProblems();
382 
383                     initProject(project, result);
384                 }
385 
386                 DependencyResolutionResult resolutionResult = null;
387 
388                 if (request.isResolveDependencies()) {
389                     projectBuildingHelper.selectProjectRealm(project);
390                     resolutionResult = resolveDependencies(project);
391                 }
392 
393                 ProjectBuildingResult result =
394                         new DefaultProjectBuildingResult(project, convert(modelProblems), resolutionResult);
395 
396                 if (error != null) {
397                     ProjectBuildingException e = new ProjectBuildingException(List.of(result));
398                     e.initCause(error);
399                     throw e;
400                 }
401 
402                 return result;
403             } finally {
404                 Thread.currentThread().setContextClassLoader(oldContextClassLoader);
405             }
406         }
407 
408         ProjectBuildingResult build(Artifact artifact, boolean allowStubModel) throws ProjectBuildingException {
409             org.eclipse.aether.artifact.Artifact pomArtifact = RepositoryUtils.toArtifact(artifact);
410             pomArtifact = ArtifactDescriptorUtils.toPomArtifact(pomArtifact);
411 
412             boolean localProject;
413 
414             try {
415                 ArtifactRequest pomRequest = new ArtifactRequest();
416                 pomRequest.setArtifact(pomArtifact);
417                 pomRequest.setRepositories(RepositoryUtils.toRepos(request.getRemoteRepositories()));
418                 ArtifactResult pomResult = repoSystem.resolveArtifact(session, pomRequest);
419 
420                 pomArtifact = pomResult.getArtifact();
421                 localProject = pomResult.getRepository() instanceof WorkspaceRepository;
422             } catch (org.eclipse.aether.resolution.ArtifactResolutionException e) {
423                 if (e.getResults().get(0).isMissing() && allowStubModel) {
424                     return build(null, createStubModelSource(artifact));
425                 }
426                 throw new ProjectBuildingException(
427                         artifact.getId(), "Error resolving project artifact: " + e.getMessage(), e);
428             }
429 
430             Path pomFile = pomArtifact.getPath();
431 
432             if (!artifact.isResolved() && "pom".equals(artifact.getType())) {
433                 artifact.selectVersion(pomArtifact.getVersion());
434                 artifact.setFile(pomFile.toFile());
435                 artifact.setResolved(true);
436             }
437 
438             if (localProject) {
439                 return build(pomFile, ModelSource.fromPath(pomFile));
440             } else {
441                 return build(
442                         null,
443                         ModelSource.fromPath(
444                                 pomFile,
445                                 artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion()));
446             }
447         }
448 
449         List<ProjectBuildingResult> build(List<File> pomFiles, boolean recursive) throws ProjectBuildingException {
450             List<ProjectBuildingResult> results = doBuild(pomFiles, recursive);
451             if (results.stream()
452                     .flatMap(r -> r.getProblems().stream())
453                     .anyMatch(p -> p.getSeverity() != org.apache.maven.model.building.ModelProblem.Severity.WARNING)) {
454                 org.apache.maven.model.building.ModelProblem cycle = results.stream()
455                         .flatMap(r -> r.getProblems().stream())
456                         .filter(p -> p.getException() instanceof CycleDetectedException)
457                         .findAny()
458                         .orElse(null);
459                 if (cycle != null) {
460                     throw new RuntimeException(new ProjectCycleException(
461                             "The projects in the reactor contain a cyclic reference: " + cycle.getMessage(),
462                             (CycleDetectedException) cycle.getException()));
463                 }
464                 throw new ProjectBuildingException(results);
465             }
466 
467             return results;
468         }
469 
470         List<ProjectBuildingResult> doBuild(List<File> pomFiles, boolean recursive) {
471             ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
472             try {
473                 return pomFiles.stream()
474                         .map(pomFile -> build(pomFile, recursive))
475                         .flatMap(List::stream)
476                         .collect(Collectors.toList());
477             } finally {
478                 Thread.currentThread().setContextClassLoader(oldContextClassLoader);
479             }
480         }
481 
482         @SuppressWarnings("checkstyle:parameternumber")
483         private List<ProjectBuildingResult> build(File pomFile, boolean recursive) {
484             ModelBuilderResult result;
485             try {
486                 ModelTransformer injector = (m, r, p) -> {
487                     MavenProject project = projectIndex.computeIfAbsent(m.getId(), f -> new MavenProject());
488                     return injectLifecycleBindings(m, r, p, project, request);
489                 };
490                 ModelBuilderRequest modelBuildingRequest = getModelBuildingRequest()
491                         .source(ModelSource.fromPath(pomFile.toPath()))
492                         .requestType(ModelBuilderRequest.RequestType.BUILD_PROJECT)
493                         .locationTracking(true)
494                         .recursive(recursive)
495                         .lifecycleBindingsInjector(injector)
496                         .build();
497                 result = modelBuilderSession.build(modelBuildingRequest);
498             } catch (ModelBuilderException e) {
499                 result = e.getResult();
500                 if (result == null || result.getEffectiveModel() == null) {
501                     return List.of(new DefaultProjectBuildingResult(e.getModelId(), pomFile, convert(e.getProblems())));
502                 }
503             }
504 
505             List<ProjectBuildingResult> results = new ArrayList<>();
506             List<ModelBuilderResult> allModels = results(result).toList();
507             for (ModelBuilderResult r : allModels) {
508                 List<ModelProblem> problems = new ArrayList<>(r.getProblems());
509                 results(r)
510                         .filter(c -> c != r)
511                         .flatMap(c -> c.getProblems().stream())
512                         .forEach(problems::remove);
513                 if (r.getEffectiveModel() != null) {
514                     File pom = r.getSource().getPath().toFile();
515                     MavenProject project =
516                             projectIndex.get(r.getEffectiveModel().getId());
517                     Path rootDirectory =
518                             rootLocator.findRoot(pom.getParentFile().toPath());
519                     project.setRootDirectory(rootDirectory);
520                     project.setFile(pom);
521                     project.setExecutionRoot(pom.equals(pomFile));
522                     initProject(project, r);
523                     project.setCollectedProjects(results(r)
524                             .filter(cr -> cr != r && cr.getEffectiveModel() != null)
525                             .map(cr -> projectIndex.get(cr.getEffectiveModel().getId()))
526                             .collect(Collectors.toList()));
527 
528                     DependencyResolutionResult resolutionResult = null;
529                     if (request.isResolveDependencies()) {
530                         resolutionResult = resolveDependencies(project);
531                     }
532                     results.add(new DefaultProjectBuildingResult(project, convert(problems), resolutionResult));
533                 } else {
534                     results.add(new DefaultProjectBuildingResult(null, convert(problems), null));
535                 }
536             }
537             return results;
538         }
539 
540         private Stream<ModelBuilderResult> results(ModelBuilderResult result) {
541             return Stream.concat(result.getChildren().stream().flatMap(this::results), Stream.of(result));
542         }
543 
544         private List<org.apache.maven.model.building.ModelProblem> convert(List<ModelProblem> problems) {
545             if (problems == null) {
546                 return null;
547             }
548             return problems.stream().map(p -> convert(p)).toList();
549         }
550 
551         private static org.apache.maven.model.building.ModelProblem convert(ModelProblem p) {
552             return new DefaultModelProblem(
553                     p.getMessage(),
554                     org.apache.maven.model.building.ModelProblem.Severity.valueOf(
555                             p.getSeverity().name()),
556                     org.apache.maven.model.building.ModelProblem.Version.valueOf(
557                             p.getVersion().name()),
558                     p.getSource(),
559                     p.getLineNumber(),
560                     p.getColumnNumber(),
561                     p.getModelId(),
562                     p.getException());
563         }
564 
565         @SuppressWarnings({"checkstyle:methodlength", "deprecation"})
566         private void initProject(MavenProject project, ModelBuilderResult result) {
567             project.setModel(new org.apache.maven.model.Model(result.getEffectiveModel()));
568             project.setOriginalModel(new org.apache.maven.model.Model(result.getFileModel()));
569 
570             initParent(project, result);
571 
572             Artifact projectArtifact = repositorySystem.createArtifact(
573                     project.getGroupId(), project.getArtifactId(), project.getVersion(), null, project.getPackaging());
574             project.setArtifact(projectArtifact);
575 
576             // only set those on 2nd phase, ignore on 1st pass
577             if (project.getFile() != null) {
578                 Build build = project.getBuild().getDelegate();
579                 project.addScriptSourceRoot(build.getScriptSourceDirectory());
580                 project.addCompileSourceRoot(build.getSourceDirectory());
581                 project.addTestCompileSourceRoot(build.getTestSourceDirectory());
582             }
583 
584             project.setActiveProfiles(
585                     Stream.concat(result.getActivePomProfiles().stream(), result.getActiveExternalProfiles().stream())
586                             .map(org.apache.maven.model.Profile::new)
587                             .toList());
588 
589             project.setInjectedProfileIds("external", getProfileIds(result.getActiveExternalProfiles()));
590             project.setInjectedProfileIds(
591                     result.getEffectiveModel().getId(), getProfileIds(result.getActivePomProfiles()));
592 
593             //
594             // All the parts that were taken out of MavenProject for Maven 4.0.0
595             //
596 
597             project.setProjectBuildingRequest(request);
598 
599             // pluginArtifacts
600             Set<Artifact> pluginArtifacts = new HashSet<>();
601             for (Plugin plugin : project.getModel().getDelegate().getBuild().getPlugins()) {
602                 Artifact artifact = repositorySystem.createPluginArtifact(new org.apache.maven.model.Plugin(plugin));
603 
604                 if (artifact != null) {
605                     pluginArtifacts.add(artifact);
606                 }
607             }
608             project.setPluginArtifacts(pluginArtifacts);
609 
610             // reportArtifacts
611             Set<Artifact> reportArtifacts = new HashSet<>();
612             for (ReportPlugin report :
613                     project.getModel().getDelegate().getReporting().getPlugins()) {
614                 Plugin pp = Plugin.newBuilder()
615                         .groupId(report.getGroupId())
616                         .artifactId(report.getArtifactId())
617                         .version(report.getVersion())
618                         .build();
619 
620                 Artifact artifact = repositorySystem.createPluginArtifact(new org.apache.maven.model.Plugin(pp));
621 
622                 if (artifact != null) {
623                     reportArtifacts.add(artifact);
624                 }
625             }
626             project.setReportArtifacts(reportArtifacts);
627 
628             // extensionArtifacts
629             Set<Artifact> extensionArtifacts = new HashSet<>();
630             List<Extension> extensions =
631                     project.getModel().getDelegate().getBuild().getExtensions();
632             if (extensions != null) {
633                 for (Extension ext : extensions) {
634                     String version;
635                     if (ext.getVersion() == null || ext.getVersion().isEmpty()) {
636                         version = "RELEASE";
637                     } else {
638                         version = ext.getVersion();
639                     }
640 
641                     Artifact artifact = repositorySystem.createArtifact(
642                             ext.getGroupId(), ext.getArtifactId(), version, null, "jar");
643 
644                     if (artifact != null) {
645                         extensionArtifacts.add(artifact);
646                     }
647                 }
648             }
649             project.setExtensionArtifacts(extensionArtifacts);
650 
651             // managedVersionMap
652             Map<String, Artifact> map = Collections.emptyMap();
653             final DependencyManagement dependencyManagement =
654                     project.getModel().getDelegate().getDependencyManagement();
655             if (dependencyManagement != null
656                     && dependencyManagement.getDependencies() != null
657                     && !dependencyManagement.getDependencies().isEmpty()) {
658                 map = new LazyMap<>(() -> {
659                     Map<String, Artifact> tmp = new HashMap<>();
660                     for (Dependency d : dependencyManagement.getDependencies()) {
661                         Artifact artifact =
662                                 repositorySystem.createDependencyArtifact(new org.apache.maven.model.Dependency(d));
663                         if (artifact != null) {
664                             tmp.put(d.getManagementKey(), artifact);
665                         }
666                     }
667                     return Collections.unmodifiableMap(tmp);
668                 });
669             }
670             project.setManagedVersionMap(map);
671 
672             // release artifact repository
673             if (project.getDistributionManagement() != null
674                     && project.getDistributionManagement().getRepository() != null) {
675                 try {
676                     DeploymentRepository r = project.getModel()
677                             .getDelegate()
678                             .getDistributionManagement()
679                             .getRepository();
680                     if (r.getId() != null
681                             && !r.getId().isEmpty()
682                             && r.getUrl() != null
683                             && !r.getUrl().isEmpty()) {
684                         ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(
685                                 new org.apache.maven.model.DeploymentRepository(r));
686                         repositorySystem.injectProxy(request.getRepositorySession(), List.of(repo));
687                         repositorySystem.injectAuthentication(request.getRepositorySession(), List.of(repo));
688                         project.setReleaseArtifactRepository(repo);
689                     }
690                 } catch (InvalidRepositoryException e) {
691                     throw new IllegalStateException(
692                             "Failed to create release distribution repository for " + project.getId(), e);
693                 }
694             }
695 
696             // snapshot artifact repository
697             if (project.getDistributionManagement() != null
698                     && project.getDistributionManagement().getSnapshotRepository() != null) {
699                 try {
700                     DeploymentRepository r = project.getModel()
701                             .getDelegate()
702                             .getDistributionManagement()
703                             .getSnapshotRepository();
704                     if (r.getId() != null
705                             && !r.getId().isEmpty()
706                             && r.getUrl() != null
707                             && !r.getUrl().isEmpty()) {
708                         ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(
709                                 new org.apache.maven.model.DeploymentRepository(r));
710                         repositorySystem.injectProxy(request.getRepositorySession(), List.of(repo));
711                         repositorySystem.injectAuthentication(request.getRepositorySession(), List.of(repo));
712                         project.setSnapshotArtifactRepository(repo);
713                     }
714                 } catch (InvalidRepositoryException e) {
715                     throw new IllegalStateException(
716                             "Failed to create snapshot distribution repository for " + project.getId(), e);
717                 }
718             }
719         }
720 
721         private void initParent(MavenProject project, ModelBuilderResult result) {
722             Model parentModel = result.getParentModel();
723 
724             if (parentModel != null) {
725                 final String parentGroupId = getGroupId(parentModel);
726                 final String parentVersion = getVersion(parentModel);
727 
728                 project.setParentArtifact(repositorySystem.createProjectArtifact(
729                         parentGroupId, parentModel.getArtifactId(), parentVersion));
730 
731                 MavenProject parent = projectIndex.get(parentModel.getId());
732                 if (parent == null) {
733                     //
734                     // At this point the DefaultModelBuildingListener has fired and it populates the
735                     // remote repositories with those found in the pom.xml, along with the existing externally
736                     // defined repositories.
737                     //
738                     request.setRemoteRepositories(project.getRemoteArtifactRepositories());
739                     Path parentPomFile = parentModel.getPomFile();
740                     if (parentPomFile != null) {
741                         project.setParentFile(parentPomFile.toFile());
742                         try {
743                             parent = build(parentPomFile, ModelSource.fromPath(parentPomFile))
744                                     .getProject();
745                         } catch (ProjectBuildingException e) {
746                             // MNG-4488 where let invalid parents slide on by
747                             if (logger.isDebugEnabled()) {
748                                 // Message below is checked for in the MNG-2199 core IT.
749                                 logger.warn("Failed to build parent project for " + project.getId(), e);
750                             } else {
751                                 // Message below is checked for in the MNG-2199 core IT.
752                                 logger.warn("Failed to build parent project for " + project.getId());
753                             }
754                         }
755                     } else {
756                         Artifact parentArtifact = project.getParentArtifact();
757                         try {
758                             parent = build(parentArtifact, false).getProject();
759                         } catch (ProjectBuildingException e) {
760                             // MNG-4488 where let invalid parents slide on by
761                             if (logger.isDebugEnabled()) {
762                                 // Message below is checked for in the MNG-2199 core IT.
763                                 logger.warn("Failed to build parent project for " + project.getId(), e);
764                             } else {
765                                 // Message below is checked for in the MNG-2199 core IT.
766                                 logger.warn("Failed to build parent project for " + project.getId());
767                             }
768                         }
769                     }
770                 }
771                 project.setParent(parent);
772                 if (project.getParentFile() == null && parent != null) {
773                     project.setParentFile(parent.getFile());
774                 }
775             }
776         }
777 
778         private ModelBuilderRequest.ModelBuilderRequestBuilder getModelBuildingRequest() {
779             ModelBuilderRequest.ModelBuilderRequestBuilder modelBuildingRequest = ModelBuilderRequest.builder();
780 
781             InternalSession internalSession = InternalSession.from(session);
782             modelBuildingRequest.session(internalSession);
783             modelBuildingRequest.requestType(ModelBuilderRequest.RequestType.BUILD_PROJECT);
784             modelBuildingRequest.profiles(
785                     request.getProfiles() != null
786                             ? request.getProfiles().stream()
787                                     .map(org.apache.maven.model.Profile::getDelegate)
788                                     .toList()
789                             : null);
790             modelBuildingRequest.activeProfileIds(request.getActiveProfileIds());
791             modelBuildingRequest.inactiveProfileIds(request.getInactiveProfileIds());
792             modelBuildingRequest.systemProperties(toMap(request.getSystemProperties()));
793             modelBuildingRequest.userProperties(toMap(request.getUserProperties()));
794             modelBuildingRequest.repositoryMerging(ModelBuilderRequest.RepositoryMerging.valueOf(
795                     request.getRepositoryMerging().name()));
796             modelBuildingRequest.repositories(request.getRemoteRepositories().stream()
797                     .map(r -> internalSession.getRemoteRepository(RepositoryUtils.toRepo(r)))
798                     .toList());
799             return modelBuildingRequest;
800         }
801 
802         private DependencyResolutionResult resolveDependencies(MavenProject project) {
803             DependencyResolutionResult resolutionResult;
804 
805             try {
806                 DefaultDependencyResolutionRequest resolution =
807                         new DefaultDependencyResolutionRequest(project, session);
808                 resolutionResult = dependencyResolver.resolve(resolution);
809             } catch (DependencyResolutionException e) {
810                 resolutionResult = e.getResult();
811             }
812 
813             Set<Artifact> artifacts = new LinkedHashSet<>();
814             if (resolutionResult.getDependencyGraph() != null) {
815                 RepositoryUtils.toArtifacts(
816                         artifacts,
817                         resolutionResult.getDependencyGraph().getChildren(),
818                         Collections.singletonList(project.getArtifact().getId()),
819                         null);
820 
821                 // Maven 2.x quirk: an artifact always points at the local repo, regardless whether resolved or not
822                 LocalRepositoryManager lrm = session.getLocalRepositoryManager();
823                 for (Artifact artifact : artifacts) {
824                     if (!artifact.isResolved()) {
825                         String path = lrm.getPathForLocalArtifact(RepositoryUtils.toArtifact(artifact));
826                         artifact.setFile(
827                                 lrm.getRepository().getBasePath().resolve(path).toFile());
828                     }
829                 }
830             }
831             project.setResolvedArtifacts(artifacts);
832             project.setArtifacts(artifacts);
833 
834             return resolutionResult;
835         }
836     }
837 
838     private List<String> getProfileIds(List<Profile> profiles) {
839         return profiles.stream().map(Profile::getId).collect(Collectors.toList());
840     }
841 
842     private static ModelSource createStubModelSource(Artifact artifact) {
843         String xml = "<?xml version='1.0'?>" + "<project>"
844                 + "<modelVersion>4.0.0</modelVersion>"
845                 + "<groupId>"
846                 + artifact.getGroupId() + "</groupId>" + "<artifactId>"
847                 + artifact.getArtifactId() + "</artifactId>" + "<version>"
848                 + artifact.getBaseVersion() + "</version>" + "<packaging>"
849                 + artifact.getType() + "</packaging>" + "</project>";
850         return new StubModelSource(xml, artifact);
851     }
852 
853     static String getGroupId(Model model) {
854         String groupId = model.getGroupId();
855         if (groupId == null && model.getParent() != null) {
856             groupId = model.getParent().getGroupId();
857         }
858         return groupId;
859     }
860 
861     static String getVersion(Model model) {
862         String version = model.getVersion();
863         if (version == null && model.getParent() != null) {
864             version = model.getParent().getVersion();
865         }
866         return version;
867     }
868 
869     private static Map<String, String> toMap(Properties properties) {
870         if (properties != null && !properties.isEmpty()) {
871             return properties.entrySet().stream()
872                     .collect(Collectors.toMap(e -> String.valueOf(e.getKey()), e -> String.valueOf(e.getValue())));
873         } else {
874             return null;
875         }
876     }
877 
878     static class LazyMap<K, V> extends AbstractMap<K, V> {
879         private final Supplier<Map<K, V>> supplier;
880         private volatile Map<K, V> delegate;
881 
882         LazyMap(Supplier<Map<K, V>> supplier) {
883             this.supplier = supplier;
884         }
885 
886         @Override
887         public Set<Entry<K, V>> entrySet() {
888             if (delegate == null) {
889                 synchronized (this) {
890                     if (delegate == null) {
891                         delegate = supplier.get();
892                     }
893                 }
894             }
895             return delegate.entrySet();
896         }
897     }
898 
899     private Model injectLifecycleBindings(
900             Model model,
901             ModelBuilderRequest request,
902             ModelProblemCollector problems,
903             MavenProject project,
904             ProjectBuildingRequest projectBuildingRequest) {
905         org.apache.maven.model.Model model3 = new org.apache.maven.model.Model(model);
906         List<ArtifactRepository> remoteRepositories = projectBuildingRequest.getRemoteRepositories();
907         List<ArtifactRepository> pluginRepositories = projectBuildingRequest.getPluginArtifactRepositories();
908         try {
909             pluginRepositories = projectBuildingHelper.createArtifactRepositories(
910                     model3.getPluginRepositories(), pluginRepositories, projectBuildingRequest);
911         } catch (Exception e) {
912             problems.add(Severity.ERROR, Version.BASE, "Invalid plugin repository: " + e.getMessage(), e);
913         }
914         project.setPluginArtifactRepositories(pluginRepositories);
915 
916         if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_PROJECT) {
917             try {
918                 ProjectRealmCache.CacheRecord record =
919                         projectBuildingHelper.createProjectRealm(project, model3, projectBuildingRequest);
920 
921                 project.setClassRealm(record.getRealm());
922                 project.setExtensionDependencyFilter(record.getExtensionArtifactFilter());
923             } catch (PluginResolutionException | PluginManagerException | PluginVersionResolutionException e) {
924 
925                 problems.add(Severity.ERROR, Version.BASE, "Unresolvable build extension: " + e.getMessage(), e);
926             }
927             projectBuildingHelper.selectProjectRealm(project);
928         }
929 
930         // build the regular repos after extensions are loaded to allow for custom layouts
931         try {
932             remoteRepositories = projectBuildingHelper.createArtifactRepositories(
933                     model3.getRepositories(), remoteRepositories, projectBuildingRequest);
934         } catch (Exception e) {
935             problems.add(Severity.ERROR, Version.BASE, "Invalid artifact repository: " + e.getMessage(), e);
936         }
937         project.setRemoteArtifactRepositories(remoteRepositories);
938 
939         if (projectBuildingRequest.isProcessPlugins()) {
940             return lifecycleBindingsInjector.injectLifecycleBindings(model3.getDelegate(), request, problems);
941         } else {
942             return model3.getDelegate();
943         }
944     }
945 }