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.File;
26  import java.io.IOException;
27  import java.util.*;
28  import java.util.concurrent.ConcurrentHashMap;
29  import java.util.concurrent.ForkJoinPool;
30  import java.util.concurrent.ForkJoinTask;
31  import java.util.function.Supplier;
32  import java.util.stream.Collectors;
33  
34  import org.apache.maven.ProjectCycleException;
35  import org.apache.maven.RepositoryUtils;
36  import org.apache.maven.api.feature.Features;
37  import org.apache.maven.artifact.Artifact;
38  import org.apache.maven.artifact.InvalidArtifactRTException;
39  import org.apache.maven.artifact.InvalidRepositoryException;
40  import org.apache.maven.artifact.repository.ArtifactRepository;
41  import org.apache.maven.bridge.MavenRepositorySystem;
42  import org.apache.maven.internal.impl.InternalSession;
43  import org.apache.maven.model.Build;
44  import org.apache.maven.model.Dependency;
45  import org.apache.maven.model.DependencyManagement;
46  import org.apache.maven.model.DeploymentRepository;
47  import org.apache.maven.model.Extension;
48  import org.apache.maven.model.Model;
49  import org.apache.maven.model.Plugin;
50  import org.apache.maven.model.Profile;
51  import org.apache.maven.model.ReportPlugin;
52  import org.apache.maven.model.building.ArtifactModelSource;
53  import org.apache.maven.model.building.DefaultModelBuilder;
54  import org.apache.maven.model.building.DefaultModelBuildingRequest;
55  import org.apache.maven.model.building.DefaultModelProblem;
56  import org.apache.maven.model.building.FileModelSource;
57  import org.apache.maven.model.building.ModelBuilder;
58  import org.apache.maven.model.building.ModelBuildingException;
59  import org.apache.maven.model.building.ModelBuildingRequest;
60  import org.apache.maven.model.building.ModelBuildingResult;
61  import org.apache.maven.model.building.ModelProblem;
62  import org.apache.maven.model.building.ModelProcessor;
63  import org.apache.maven.model.building.ModelSource;
64  import org.apache.maven.model.building.StringModelSource;
65  import org.apache.maven.model.building.TransformerContext;
66  import org.apache.maven.model.building.TransformerContextBuilder;
67  import org.apache.maven.model.resolution.ModelResolver;
68  import org.apache.maven.model.root.RootLocator;
69  import org.apache.maven.repository.internal.ArtifactDescriptorUtils;
70  import org.apache.maven.repository.internal.ModelCacheFactory;
71  import org.apache.maven.utils.Os;
72  import org.eclipse.aether.RepositorySystem;
73  import org.eclipse.aether.RepositorySystemSession;
74  import org.eclipse.aether.RequestTrace;
75  import org.eclipse.aether.impl.RemoteRepositoryManager;
76  import org.eclipse.aether.repository.LocalRepositoryManager;
77  import org.eclipse.aether.repository.RemoteRepository;
78  import org.eclipse.aether.repository.WorkspaceRepository;
79  import org.eclipse.aether.resolution.ArtifactRequest;
80  import org.eclipse.aether.resolution.ArtifactResult;
81  import org.slf4j.Logger;
82  import org.slf4j.LoggerFactory;
83  
84  /**
85   * DefaultProjectBuilder
86   */
87  @Named
88  @Singleton
89  public class DefaultProjectBuilder implements ProjectBuilder {
90      public static final String BUILDER_PARALLELISM = "maven.projectBuilder.parallelism";
91      public static final int DEFAULT_BUILDER_PARALLELISM = 4;
92  
93      private final Logger logger = LoggerFactory.getLogger(getClass());
94      private final ModelBuilder modelBuilder;
95      private final ModelProcessor modelProcessor;
96      private final ProjectBuildingHelper projectBuildingHelper;
97      private final MavenRepositorySystem repositorySystem;
98      private final org.eclipse.aether.RepositorySystem repoSystem;
99      private final RemoteRepositoryManager repositoryManager;
100     private final ProjectDependenciesResolver dependencyResolver;
101     private final ModelCacheFactory modelCacheFactory;
102 
103     private final RootLocator rootLocator;
104 
105     @SuppressWarnings("checkstyle:ParameterNumber")
106     @Inject
107     public DefaultProjectBuilder(
108             ModelBuilder modelBuilder,
109             ModelProcessor modelProcessor,
110             ProjectBuildingHelper projectBuildingHelper,
111             MavenRepositorySystem repositorySystem,
112             RepositorySystem repoSystem,
113             RemoteRepositoryManager repositoryManager,
114             ProjectDependenciesResolver dependencyResolver,
115             ModelCacheFactory modelCacheFactory,
116             RootLocator rootLocator) {
117         this.modelBuilder = modelBuilder;
118         this.modelProcessor = modelProcessor;
119         this.projectBuildingHelper = projectBuildingHelper;
120         this.repositorySystem = repositorySystem;
121         this.repoSystem = repoSystem;
122         this.repositoryManager = repositoryManager;
123         this.dependencyResolver = dependencyResolver;
124         this.modelCacheFactory = modelCacheFactory;
125         this.rootLocator = rootLocator;
126     }
127     // ----------------------------------------------------------------------
128     // MavenProjectBuilder Implementation
129     // ----------------------------------------------------------------------
130 
131     @Override
132     public ProjectBuildingResult build(File pomFile, ProjectBuildingRequest request) throws ProjectBuildingException {
133         try (BuildSession bs = new BuildSession(request, false)) {
134             return bs.build(pomFile, new FileModelSource(pomFile));
135         }
136     }
137 
138     @Override
139     public ProjectBuildingResult build(ModelSource modelSource, ProjectBuildingRequest request)
140             throws ProjectBuildingException {
141         try (BuildSession bs = new BuildSession(request, false)) {
142             return bs.build(null, modelSource);
143         }
144     }
145 
146     @Override
147     public ProjectBuildingResult build(Artifact artifact, ProjectBuildingRequest request)
148             throws ProjectBuildingException {
149         return build(artifact, false, request);
150     }
151 
152     @Override
153     public ProjectBuildingResult build(Artifact artifact, boolean allowStubModel, ProjectBuildingRequest request)
154             throws ProjectBuildingException {
155         try (BuildSession bs = new BuildSession(request, false)) {
156             return bs.build(artifact, allowStubModel);
157         }
158     }
159 
160     @Override
161     public List<ProjectBuildingResult> build(List<File> pomFiles, boolean recursive, ProjectBuildingRequest request)
162             throws ProjectBuildingException {
163         try (BuildSession bs = new BuildSession(request, true)) {
164             return bs.build(pomFiles, recursive);
165         }
166     }
167 
168     static class InterimResult {
169 
170         File pomFile;
171 
172         ModelBuildingRequest request;
173 
174         ModelBuildingResult result;
175 
176         MavenProject project;
177 
178         boolean root;
179 
180         List<InterimResult> modules = Collections.emptyList();
181 
182         ProjectBuildingResult projectBuildingResult;
183 
184         InterimResult(
185                 File pomFile,
186                 ModelBuildingRequest request,
187                 ModelBuildingResult result,
188                 MavenProject project,
189                 boolean root) {
190             this.pomFile = pomFile;
191             this.request = request;
192             this.result = result;
193             this.project = project;
194             this.root = root;
195         }
196 
197         InterimResult(ModelBuildingRequest request, ProjectBuildingResult projectBuildingResult) {
198             this.request = request;
199             this.projectBuildingResult = projectBuildingResult;
200             this.pomFile = projectBuildingResult.getPomFile();
201             this.project = projectBuildingResult.getProject();
202         }
203     }
204 
205     class BuildSession implements AutoCloseable {
206         private final ProjectBuildingRequest request;
207         private final RepositorySystemSession session;
208         private final List<RemoteRepository> repositories;
209         private final ReactorModelPool modelPool;
210         private final TransformerContextBuilder transformerContextBuilder;
211         private final ForkJoinPool forkJoinPool;
212 
213         BuildSession(ProjectBuildingRequest request, boolean localProjects) {
214             this.request = request;
215             this.session =
216                     RepositoryUtils.overlay(request.getLocalRepository(), request.getRepositorySession(), repoSystem);
217             this.repositories = RepositoryUtils.toRepos(request.getRemoteRepositories());
218             this.forkJoinPool = new ForkJoinPool(getParallelism(request));
219             if (localProjects) {
220                 this.modelPool = new ReactorModelPool();
221                 this.transformerContextBuilder = modelBuilder.newTransformerContextBuilder();
222             } else {
223                 this.modelPool = null;
224                 this.transformerContextBuilder = null;
225             }
226         }
227 
228         @Override
229         public void close() {
230             this.forkJoinPool.shutdownNow();
231         }
232 
233         private int getParallelism(ProjectBuildingRequest request) {
234             int parallelism = DEFAULT_BUILDER_PARALLELISM;
235             try {
236                 String str = request.getUserProperties().getProperty(BUILDER_PARALLELISM);
237                 if (str == null) {
238                     str = request.getSystemProperties().getProperty(BUILDER_PARALLELISM);
239                 }
240                 if (str != null) {
241                     parallelism = Integer.parseInt(str);
242                 }
243             } catch (Exception e) {
244                 // ignore
245             }
246             return Math.max(1, Math.min(parallelism, Runtime.getRuntime().availableProcessors()));
247         }
248 
249         ProjectBuildingResult build(File pomFile, ModelSource modelSource) throws ProjectBuildingException {
250             ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
251 
252             try {
253                 MavenProject project = request.getProject();
254 
255                 List<ModelProblem> modelProblems = null;
256                 Throwable error = null;
257 
258                 if (project == null) {
259                     ModelBuildingRequest request = getModelBuildingRequest();
260 
261                     project = new MavenProject();
262                     project.setFile(pomFile);
263 
264                     DefaultModelBuildingListener listener =
265                             new DefaultModelBuildingListener(project, projectBuildingHelper, this.request);
266                     request.setModelBuildingListener(listener);
267 
268                     request.setPomFile(pomFile);
269                     request.setModelSource(modelSource);
270                     request.setLocationTracking(true);
271 
272                     if (pomFile != null) {
273                         project.setRootDirectory(
274                                 rootLocator.findRoot(pomFile.getParentFile().toPath()));
275                     }
276 
277                     ModelBuildingResult result;
278                     try {
279                         result = modelBuilder.build(request);
280                     } catch (ModelBuildingException e) {
281                         result = e.getResult();
282                         if (result == null || result.getEffectiveModel() == null) {
283                             throw new ProjectBuildingException(e.getModelId(), e.getMessage(), pomFile, e);
284                         }
285                         // validation error, continue project building and delay failing to help IDEs
286                         error = e;
287                     }
288 
289                     modelProblems = result.getProblems();
290 
291                     initProject(project, Collections.emptyMap(), result);
292                 } else if (request.isResolveDependencies()) {
293                     projectBuildingHelper.selectProjectRealm(project);
294                 }
295 
296                 DependencyResolutionResult resolutionResult = null;
297 
298                 if (request.isResolveDependencies()) {
299                     resolutionResult = resolveDependencies(project);
300                 }
301 
302                 ProjectBuildingResult result =
303                         new DefaultProjectBuildingResult(project, modelProblems, resolutionResult);
304 
305                 if (error != null) {
306                     ProjectBuildingException e = new ProjectBuildingException(Arrays.asList(result));
307                     e.initCause(error);
308                     throw e;
309                 }
310 
311                 return result;
312             } finally {
313                 Thread.currentThread().setContextClassLoader(oldContextClassLoader);
314             }
315         }
316 
317         ProjectBuildingResult build(Artifact artifact, boolean allowStubModel) throws ProjectBuildingException {
318             org.eclipse.aether.artifact.Artifact pomArtifact = RepositoryUtils.toArtifact(artifact);
319             pomArtifact = ArtifactDescriptorUtils.toPomArtifact(pomArtifact);
320 
321             boolean localProject;
322 
323             try {
324                 ArtifactRequest pomRequest = new ArtifactRequest();
325                 pomRequest.setArtifact(pomArtifact);
326                 pomRequest.setRepositories(repositories);
327                 ArtifactResult pomResult = repoSystem.resolveArtifact(session, pomRequest);
328 
329                 pomArtifact = pomResult.getArtifact();
330                 localProject = pomResult.getRepository() instanceof WorkspaceRepository;
331             } catch (org.eclipse.aether.resolution.ArtifactResolutionException e) {
332                 if (e.getResults().get(0).isMissing() && allowStubModel) {
333                     return build(null, createStubModelSource(artifact));
334                 }
335                 throw new ProjectBuildingException(
336                         artifact.getId(), "Error resolving project artifact: " + e.getMessage(), e);
337             }
338 
339             File pomFile = pomArtifact.getFile();
340 
341             if ("pom".equals(artifact.getType())) {
342                 artifact.selectVersion(pomArtifact.getVersion());
343                 artifact.setFile(pomFile);
344                 artifact.setResolved(true);
345             }
346 
347             if (localProject) {
348                 return build(pomFile, new FileModelSource(pomFile));
349             } else {
350                 return build(
351                         null,
352                         new ArtifactModelSource(
353                                 pomFile, artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()));
354             }
355         }
356 
357         List<ProjectBuildingResult> build(List<File> pomFiles, boolean recursive) throws ProjectBuildingException {
358             ForkJoinTask<List<ProjectBuildingResult>> task = forkJoinPool.submit(() -> doBuild(pomFiles, recursive));
359 
360             // ForkJoinTask.getException rewraps the exception in a weird way
361             // which cause an additional layer of exception, so try to unwrap it
362             task.quietlyJoin();
363             if (task.isCompletedAbnormally()) {
364                 Throwable e = task.getException();
365                 Throwable c = e.getCause();
366                 uncheckedThrow(c != null && c.getClass() == e.getClass() ? c : e);
367             }
368 
369             List<ProjectBuildingResult> results = task.getRawResult();
370             if (results.stream()
371                     .flatMap(r -> r.getProblems().stream())
372                     .anyMatch(p -> p.getSeverity() != ModelProblem.Severity.WARNING)) {
373                 ModelProblem cycle = results.stream()
374                         .flatMap(r -> r.getProblems().stream())
375                         .filter(p -> p.getException() instanceof CycleDetectedException)
376                         .findAny()
377                         .orElse(null);
378                 if (cycle != null) {
379                     throw new RuntimeException(new ProjectCycleException(
380                             "The projects in the reactor contain a cyclic reference: " + cycle.getMessage(),
381                             (CycleDetectedException) cycle.getException()));
382                 }
383                 throw new ProjectBuildingException(results);
384             }
385 
386             return results;
387         }
388 
389         List<ProjectBuildingResult> doBuild(List<File> pomFiles, boolean recursive) {
390             Map<File, MavenProject> projectIndex = new ConcurrentHashMap<>(256);
391 
392             // phase 1: get file Models from the reactor.
393             List<InterimResult> interimResults = build(projectIndex, pomFiles, new LinkedHashSet<>(), true, recursive);
394 
395             ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
396 
397             try {
398                 // Phase 2: get effective models from the reactor
399                 List<ProjectBuildingResult> results = build(projectIndex, interimResults);
400 
401                 if (Features.buildConsumer(request.getUserProperties())) {
402                     request.getRepositorySession()
403                             .getData()
404                             .set(TransformerContext.KEY, transformerContextBuilder.build());
405                 }
406 
407                 return results;
408             } finally {
409                 Thread.currentThread().setContextClassLoader(oldContextClassLoader);
410             }
411         }
412 
413         @SuppressWarnings("checkstyle:parameternumber")
414         private List<InterimResult> build(
415                 Map<File, MavenProject> projectIndex,
416                 List<File> pomFiles,
417                 Set<File> aggregatorFiles,
418                 boolean root,
419                 boolean recursive) {
420             List<ForkJoinTask<InterimResult>> tasks = pomFiles.stream()
421                     .map(pomFile -> ForkJoinTask.adapt(
422                             () -> build(projectIndex, pomFile, concat(aggregatorFiles, pomFile), root, recursive)))
423                     .collect(Collectors.toList());
424 
425             return ForkJoinTask.invokeAll(tasks).stream()
426                     .map(ForkJoinTask::getRawResult)
427                     .collect(Collectors.toList());
428         }
429 
430         private <T> Set<T> concat(Set<T> set, T elem) {
431             Set<T> newSet = new HashSet<>(set);
432             newSet.add(elem);
433             return newSet;
434         }
435 
436         @SuppressWarnings("checkstyle:parameternumber")
437         private InterimResult build(
438                 Map<File, MavenProject> projectIndex,
439                 File pomFile,
440                 Set<File> aggregatorFiles,
441                 boolean isRoot,
442                 boolean recursive) {
443             MavenProject project = new MavenProject();
444             project.setFile(pomFile);
445 
446             project.setRootDirectory(
447                     rootLocator.findRoot(pomFile.getParentFile().toPath()));
448 
449             ModelBuildingRequest modelBuildingRequest = getModelBuildingRequest()
450                     .setPomFile(pomFile)
451                     .setTwoPhaseBuilding(true)
452                     .setLocationTracking(true);
453 
454             DefaultModelBuildingListener listener =
455                     new DefaultModelBuildingListener(project, projectBuildingHelper, request);
456             modelBuildingRequest.setModelBuildingListener(listener);
457 
458             ModelBuildingResult result;
459             try {
460                 result = modelBuilder.build(modelBuildingRequest);
461             } catch (ModelBuildingException e) {
462                 result = e.getResult();
463                 if (result == null || result.getFileModel() == null) {
464                     return new InterimResult(
465                             modelBuildingRequest,
466                             new DefaultProjectBuildingResult(e.getModelId(), pomFile, e.getProblems()));
467                 }
468                 // validation error, continue project building and delay failing to help IDEs
469                 // result.getProblems().addAll(e.getProblems()) ?
470             }
471 
472             Model model = modelBuildingRequest.getFileModel();
473 
474             modelPool.put(model.getPomFile().toPath(), model);
475 
476             InterimResult interimResult = new InterimResult(pomFile, modelBuildingRequest, result, project, isRoot);
477 
478             if (recursive) {
479                 File basedir = pomFile.getParentFile();
480                 List<File> moduleFiles = new ArrayList<>();
481                 for (String module : model.getModules()) {
482                     if (module == null || module.isEmpty()) {
483                         continue;
484                     }
485 
486                     module = module.replace('\\', File.separatorChar).replace('/', File.separatorChar);
487 
488                     File moduleFile = modelProcessor.locateExistingPom(new File(basedir, module));
489 
490                     if (moduleFile == null) {
491                         ModelProblem problem = new DefaultModelProblem(
492                                 "Child module " + moduleFile + " of " + pomFile + " does not exist",
493                                 ModelProblem.Severity.ERROR,
494                                 ModelProblem.Version.BASE,
495                                 model,
496                                 -1,
497                                 -1,
498                                 null);
499                         result.getProblems().add(problem);
500 
501                         continue;
502                     }
503 
504                     if (Os.IS_WINDOWS) {
505                         // we don't canonicalize on unix to avoid interfering with symlinks
506                         try {
507                             moduleFile = moduleFile.getCanonicalFile();
508                         } catch (IOException e) {
509                             moduleFile = moduleFile.getAbsoluteFile();
510                         }
511                     } else {
512                         moduleFile = new File(moduleFile.toURI().normalize());
513                     }
514 
515                     if (aggregatorFiles.contains(moduleFile)) {
516                         StringBuilder buffer = new StringBuilder(256);
517                         for (File aggregatorFile : aggregatorFiles) {
518                             buffer.append(aggregatorFile).append(" -> ");
519                         }
520                         buffer.append(moduleFile);
521 
522                         ModelProblem problem = new DefaultModelProblem(
523                                 "Child module " + moduleFile + " of " + pomFile + " forms aggregation cycle " + buffer,
524                                 ModelProblem.Severity.ERROR,
525                                 ModelProblem.Version.BASE,
526                                 model,
527                                 -1,
528                                 -1,
529                                 null);
530                         result.getProblems().add(problem);
531 
532                         continue;
533                     }
534 
535                     moduleFiles.add(moduleFile);
536                 }
537 
538                 if (!moduleFiles.isEmpty()) {
539                     interimResult.modules = build(projectIndex, moduleFiles, aggregatorFiles, false, recursive);
540                 }
541             }
542 
543             projectIndex.put(pomFile, project);
544 
545             return interimResult;
546         }
547 
548         private List<ProjectBuildingResult> build(
549                 Map<File, MavenProject> projectIndex, List<InterimResult> interimResults) {
550             // The transformation may need to access dependencies raw models,
551             // which may cause some re-entrance in the build() method and can
552             // actually cause deadlocks.  In order to workaround the problem,
553             // we do a first pass by reading all rawModels in order.
554             if (modelBuilder instanceof DefaultModelBuilder) {
555                 List<ProjectBuildingResult> results = new ArrayList<>();
556                 DefaultModelBuilder dmb = (DefaultModelBuilder) modelBuilder;
557                 boolean failure = false;
558                 for (InterimResult r : interimResults) {
559                     DefaultProjectBuildingResult res;
560                     try {
561                         Model model = dmb.buildRawModel(r.request);
562                         res = new DefaultProjectBuildingResult(model.getId(), model.getPomFile(), null);
563                     } catch (ModelBuildingException e) {
564                         failure = true;
565                         res = new DefaultProjectBuildingResult(e.getModelId(), r.request.getPomFile(), e.getProblems());
566                     }
567                     results.add(res);
568                 }
569                 if (failure) {
570                     return results;
571                 }
572             }
573 
574             return interimResults.parallelStream()
575                     .map(interimResult -> doBuild(projectIndex, interimResult))
576                     .flatMap(List::stream)
577                     .collect(Collectors.toList());
578         }
579 
580         private List<ProjectBuildingResult> doBuild(Map<File, MavenProject> projectIndex, InterimResult interimResult) {
581             if (interimResult.projectBuildingResult != null) {
582                 return Collections.singletonList(interimResult.projectBuildingResult);
583             }
584             MavenProject project = interimResult.project;
585             try {
586                 ModelBuildingResult result = modelBuilder.build(interimResult.request, interimResult.result);
587 
588                 // 2nd pass of initialization: resolve and build parent if necessary
589                 try {
590                     initProject(project, projectIndex, result);
591                 } catch (InvalidArtifactRTException iarte) {
592                     result.getProblems()
593                             .add(new DefaultModelProblem(
594                                     null,
595                                     ModelProblem.Severity.ERROR,
596                                     null,
597                                     result.getEffectiveModel(),
598                                     -1,
599                                     -1,
600                                     iarte));
601                 }
602 
603                 List<ProjectBuildingResult> results = build(projectIndex, interimResult.modules);
604 
605                 project.setExecutionRoot(interimResult.root);
606                 project.setCollectedProjects(
607                         results.stream().map(ProjectBuildingResult::getProject).collect(Collectors.toList()));
608                 DependencyResolutionResult resolutionResult = null;
609                 if (request.isResolveDependencies()) {
610                     resolutionResult = resolveDependencies(project);
611                 }
612 
613                 results.add(new DefaultProjectBuildingResult(project, result.getProblems(), resolutionResult));
614 
615                 return results;
616             } catch (ModelBuildingException e) {
617                 DefaultProjectBuildingResult result;
618                 if (project == null || interimResult.result.getEffectiveModel() == null) {
619                     result = new DefaultProjectBuildingResult(e.getModelId(), interimResult.pomFile, e.getProblems());
620                 } else {
621                     project.setModel(interimResult.result.getEffectiveModel());
622                     result = new DefaultProjectBuildingResult(project, e.getProblems(), null);
623                 }
624                 return Collections.singletonList(result);
625             }
626         }
627 
628         @SuppressWarnings("checkstyle:methodlength")
629         private void initProject(MavenProject project, Map<File, MavenProject> projects, ModelBuildingResult result) {
630             project.setModel(result.getEffectiveModel());
631             project.setOriginalModel(result.getFileModel());
632 
633             initParent(project, projects, result);
634 
635             Artifact projectArtifact = repositorySystem.createArtifact(
636                     project.getGroupId(), project.getArtifactId(), project.getVersion(), null, project.getPackaging());
637             project.setArtifact(projectArtifact);
638 
639             // only set those on 2nd phase, ignore on 1st pass
640             if (project.getFile() != null) {
641                 Build build = project.getBuild();
642                 project.addScriptSourceRoot(build.getScriptSourceDirectory());
643                 project.addCompileSourceRoot(build.getSourceDirectory());
644                 project.addTestCompileSourceRoot(build.getTestSourceDirectory());
645             }
646 
647             List<Profile> activeProfiles = new ArrayList<>();
648             activeProfiles.addAll(
649                     result.getActivePomProfiles(result.getModelIds().get(0)));
650             activeProfiles.addAll(result.getActiveExternalProfiles());
651             project.setActiveProfiles(activeProfiles);
652 
653             project.setInjectedProfileIds("external", getProfileIds(result.getActiveExternalProfiles()));
654             for (String modelId : result.getModelIds()) {
655                 project.setInjectedProfileIds(modelId, getProfileIds(result.getActivePomProfiles(modelId)));
656             }
657 
658             //
659             // All the parts that were taken out of MavenProject for Maven 4.0.0
660             //
661 
662             project.setProjectBuildingRequest(request);
663 
664             // pluginArtifacts
665             Set<Artifact> pluginArtifacts = new HashSet<>();
666             for (Plugin plugin : project.getBuildPlugins()) {
667                 Artifact artifact = repositorySystem.createPluginArtifact(plugin);
668 
669                 if (artifact != null) {
670                     pluginArtifacts.add(artifact);
671                 }
672             }
673             project.setPluginArtifacts(pluginArtifacts);
674 
675             // reportArtifacts
676             Set<Artifact> reportArtifacts = new HashSet<>();
677             for (ReportPlugin report : project.getReportPlugins()) {
678                 Plugin pp = new Plugin();
679                 pp.setGroupId(report.getGroupId());
680                 pp.setArtifactId(report.getArtifactId());
681                 pp.setVersion(report.getVersion());
682 
683                 Artifact artifact = repositorySystem.createPluginArtifact(pp);
684 
685                 if (artifact != null) {
686                     reportArtifacts.add(artifact);
687                 }
688             }
689             project.setReportArtifacts(reportArtifacts);
690 
691             // extensionArtifacts
692             Set<Artifact> extensionArtifacts = new HashSet<>();
693             List<Extension> extensions = project.getBuildExtensions();
694             if (extensions != null) {
695                 for (Extension ext : extensions) {
696                     String version;
697                     if (ext.getVersion() == null || ext.getVersion().isEmpty()) {
698                         version = "RELEASE";
699                     } else {
700                         version = ext.getVersion();
701                     }
702 
703                     Artifact artifact = repositorySystem.createArtifact(
704                             ext.getGroupId(), ext.getArtifactId(), version, null, "jar");
705 
706                     if (artifact != null) {
707                         extensionArtifacts.add(artifact);
708                     }
709                 }
710             }
711             project.setExtensionArtifacts(extensionArtifacts);
712 
713             // managedVersionMap
714             Map<String, Artifact> map = Collections.emptyMap();
715             final DependencyManagement dependencyManagement = project.getDependencyManagement();
716             if (dependencyManagement != null
717                     && dependencyManagement.getDependencies() != null
718                     && !dependencyManagement.getDependencies().isEmpty()) {
719                 map = new LazyMap<>(() -> {
720                     Map<String, Artifact> tmp = new HashMap<>();
721                     for (Dependency d : dependencyManagement.getDependencies()) {
722                         Artifact artifact = repositorySystem.createDependencyArtifact(d);
723                         if (artifact != null) {
724                             tmp.put(d.getManagementKey(), artifact);
725                         }
726                     }
727                     return Collections.unmodifiableMap(tmp);
728                 });
729             }
730             project.setManagedVersionMap(map);
731 
732             // release artifact repository
733             if (project.getDistributionManagement() != null
734                     && project.getDistributionManagement().getRepository() != null) {
735                 try {
736                     DeploymentRepository r = project.getDistributionManagement().getRepository();
737                     if (r.getId() != null
738                             && !r.getId().isEmpty()
739                             && r.getUrl() != null
740                             && !r.getUrl().isEmpty()) {
741                         ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(r);
742                         repositorySystem.injectProxy(request.getRepositorySession(), Arrays.asList(repo));
743                         repositorySystem.injectAuthentication(request.getRepositorySession(), Arrays.asList(repo));
744                         project.setReleaseArtifactRepository(repo);
745                     }
746                 } catch (InvalidRepositoryException e) {
747                     throw new IllegalStateException(
748                             "Failed to create release distribution repository for " + project.getId(), e);
749                 }
750             }
751 
752             // snapshot artifact repository
753             if (project.getDistributionManagement() != null
754                     && project.getDistributionManagement().getSnapshotRepository() != null) {
755                 try {
756                     DeploymentRepository r = project.getDistributionManagement().getSnapshotRepository();
757                     if (r.getId() != null
758                             && !r.getId().isEmpty()
759                             && r.getUrl() != null
760                             && !r.getUrl().isEmpty()) {
761                         ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(r);
762                         repositorySystem.injectProxy(request.getRepositorySession(), Arrays.asList(repo));
763                         repositorySystem.injectAuthentication(request.getRepositorySession(), Arrays.asList(repo));
764                         project.setSnapshotArtifactRepository(repo);
765                     }
766                 } catch (InvalidRepositoryException e) {
767                     throw new IllegalStateException(
768                             "Failed to create snapshot distribution repository for " + project.getId(), e);
769                 }
770             }
771         }
772 
773         private void initParent(MavenProject project, Map<File, MavenProject> projects, ModelBuildingResult result) {
774             Model parentModel = result.getModelIds().size() > 1
775                             && !result.getModelIds().get(1).isEmpty()
776                     ? result.getRawModel(result.getModelIds().get(1))
777                     : null;
778 
779             if (parentModel != null) {
780                 final String parentGroupId = inheritedGroupId(result, 1);
781                 final String parentVersion = inheritedVersion(result, 1);
782 
783                 project.setParentArtifact(repositorySystem.createProjectArtifact(
784                         parentGroupId, parentModel.getArtifactId(), parentVersion));
785 
786                 // org.apache.maven.its.mng4834:parent:0.1
787                 String parentModelId = result.getModelIds().get(1);
788                 File parentPomFile = result.getRawModel(parentModelId).getPomFile();
789                 MavenProject parent = parentPomFile != null ? projects.get(parentPomFile) : null;
790                 if (parent == null) {
791                     //
792                     // At this point the DefaultModelBuildingListener has fired and it populates the
793                     // remote repositories with those found in the pom.xml, along with the existing externally
794                     // defined repositories.
795                     //
796                     request.setRemoteRepositories(project.getRemoteArtifactRepositories());
797                     if (parentPomFile != null) {
798                         project.setParentFile(parentPomFile);
799                         try {
800                             parent = build(parentPomFile, new FileModelSource(parentPomFile))
801                                     .getProject();
802                         } catch (ProjectBuildingException e) {
803                             // MNG-4488 where let invalid parents slide on by
804                             if (logger.isDebugEnabled()) {
805                                 // Message below is checked for in the MNG-2199 core IT.
806                                 logger.warn("Failed to build parent project for " + project.getId(), e);
807                             } else {
808                                 // Message below is checked for in the MNG-2199 core IT.
809                                 logger.warn("Failed to build parent project for " + project.getId());
810                             }
811                         }
812                     } else {
813                         Artifact parentArtifact = project.getParentArtifact();
814                         try {
815                             parent = build(parentArtifact, false).getProject();
816                         } catch (ProjectBuildingException e) {
817                             // MNG-4488 where let invalid parents slide on by
818                             if (logger.isDebugEnabled()) {
819                                 // Message below is checked for in the MNG-2199 core IT.
820                                 logger.warn("Failed to build parent project for " + project.getId(), e);
821                             } else {
822                                 // Message below is checked for in the MNG-2199 core IT.
823                                 logger.warn("Failed to build parent project for " + project.getId());
824                             }
825                         }
826                     }
827                 }
828                 project.setParent(parent);
829                 if (project.getParentFile() == null && parent != null) {
830                     project.setParentFile(parent.getFile());
831                 }
832             }
833         }
834 
835         private ModelBuildingRequest getModelBuildingRequest() {
836             ModelBuildingRequest modelBuildingRequest = new DefaultModelBuildingRequest();
837 
838             RequestTrace trace = RequestTrace.newChild(null, request).newChild(modelBuildingRequest);
839 
840             ModelResolver resolver = new ProjectModelResolver(
841                     session,
842                     trace,
843                     repoSystem,
844                     repositoryManager,
845                     repositories,
846                     request.getRepositoryMerging(),
847                     modelPool);
848 
849             modelBuildingRequest.setValidationLevel(request.getValidationLevel());
850             modelBuildingRequest.setProcessPlugins(request.isProcessPlugins());
851             modelBuildingRequest.setProfiles(request.getProfiles());
852             modelBuildingRequest.setActiveProfileIds(request.getActiveProfileIds());
853             modelBuildingRequest.setInactiveProfileIds(request.getInactiveProfileIds());
854             modelBuildingRequest.setSystemProperties(request.getSystemProperties());
855             modelBuildingRequest.setUserProperties(request.getUserProperties());
856             modelBuildingRequest.setBuildStartTime(request.getBuildStartTime());
857             modelBuildingRequest.setModelResolver(resolver);
858             // this is a hint that we want to build 1 file, so don't cache. See MNG-7063
859             if (modelPool != null) {
860                 modelBuildingRequest.setModelCache(modelCacheFactory.createCache(session));
861             }
862             modelBuildingRequest.setTransformerContextBuilder(transformerContextBuilder);
863             InternalSession session = (InternalSession) this.session.getData().get(InternalSession.class);
864             if (session != null) {
865                 try {
866                     modelBuildingRequest.setRootDirectory(session.getRootDirectory());
867                 } catch (IllegalStateException e) {
868                     // can happen if root directory cannot be found, just ignore
869                 }
870             }
871 
872             return modelBuildingRequest;
873         }
874 
875         private DependencyResolutionResult resolveDependencies(MavenProject project) {
876             DependencyResolutionResult resolutionResult;
877 
878             try {
879                 DefaultDependencyResolutionRequest resolution =
880                         new DefaultDependencyResolutionRequest(project, session);
881                 resolutionResult = dependencyResolver.resolve(resolution);
882             } catch (DependencyResolutionException e) {
883                 resolutionResult = e.getResult();
884             }
885 
886             Set<Artifact> artifacts = new LinkedHashSet<>();
887             if (resolutionResult.getDependencyGraph() != null) {
888                 RepositoryUtils.toArtifacts(
889                         artifacts,
890                         resolutionResult.getDependencyGraph().getChildren(),
891                         Collections.singletonList(project.getArtifact().getId()),
892                         null);
893 
894                 // Maven 2.x quirk: an artifact always points at the local repo, regardless whether resolved or not
895                 LocalRepositoryManager lrm = session.getLocalRepositoryManager();
896                 for (Artifact artifact : artifacts) {
897                     if (!artifact.isResolved()) {
898                         String path = lrm.getPathForLocalArtifact(RepositoryUtils.toArtifact(artifact));
899                         artifact.setFile(new File(lrm.getRepository().getBasedir(), path));
900                     }
901                 }
902             }
903             project.setResolvedArtifacts(artifacts);
904             project.setArtifacts(artifacts);
905 
906             return resolutionResult;
907         }
908     }
909 
910     private List<String> getProfileIds(List<org.apache.maven.model.Profile> profiles) {
911         return profiles.stream().map(org.apache.maven.model.Profile::getId).collect(Collectors.toList());
912     }
913 
914     private static ModelSource createStubModelSource(Artifact artifact) {
915         StringBuilder buffer = new StringBuilder(1024);
916 
917         buffer.append("<?xml version='1.0'?>");
918         buffer.append("<project>");
919         buffer.append("<modelVersion>4.0.0</modelVersion>");
920         buffer.append("<groupId>").append(artifact.getGroupId()).append("</groupId>");
921         buffer.append("<artifactId>").append(artifact.getArtifactId()).append("</artifactId>");
922         buffer.append("<version>").append(artifact.getBaseVersion()).append("</version>");
923         buffer.append("<packaging>").append(artifact.getType()).append("</packaging>");
924         buffer.append("</project>");
925 
926         return new StringModelSource(buffer, artifact.getId());
927     }
928 
929     private static String inheritedGroupId(final ModelBuildingResult result, final int modelIndex) {
930         String groupId = null;
931         final String modelId = result.getModelIds().get(modelIndex);
932 
933         if (!modelId.isEmpty()) {
934             final Model model = result.getRawModel(modelId);
935             groupId = model.getGroupId() != null ? model.getGroupId() : inheritedGroupId(result, modelIndex + 1);
936         }
937 
938         return groupId;
939     }
940 
941     private static String inheritedVersion(final ModelBuildingResult result, final int modelIndex) {
942         String version = null;
943         final String modelId = result.getModelIds().get(modelIndex);
944 
945         if (!modelId.isEmpty()) {
946             version = result.getRawModel(modelId).getVersion();
947             if (version == null) {
948                 version = inheritedVersion(result, modelIndex + 1);
949             }
950         }
951 
952         return version;
953     }
954 
955     static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
956         throw (T) t; // rely on vacuous cast
957     }
958 
959     static class LazyMap<K, V> extends AbstractMap<K, V> {
960         private final Supplier<Map<K, V>> supplier;
961         private volatile Map<K, V> delegate;
962 
963         LazyMap(Supplier<Map<K, V>> supplier) {
964             this.supplier = supplier;
965         }
966 
967         @Override
968         public Set<Entry<K, V>> entrySet() {
969             if (delegate == null) {
970                 synchronized (this) {
971                     if (delegate == null) {
972                         delegate = supplier.get();
973                     }
974                 }
975             }
976             return delegate.entrySet();
977         }
978     }
979 }