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