1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.project;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.ByteArrayInputStream;
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.nio.charset.StandardCharsets;
30 import java.nio.file.Path;
31 import java.util.*;
32 import java.util.concurrent.*;
33 import java.util.concurrent.atomic.AtomicInteger;
34 import java.util.concurrent.atomic.AtomicReference;
35 import java.util.function.Supplier;
36 import java.util.stream.Collectors;
37 import java.util.stream.Stream;
38
39 import org.apache.maven.ProjectCycleException;
40 import org.apache.maven.RepositoryUtils;
41 import org.apache.maven.api.Session;
42 import org.apache.maven.api.feature.Features;
43 import org.apache.maven.api.model.*;
44 import org.apache.maven.api.services.MavenException;
45 import org.apache.maven.api.services.ModelBuilder;
46 import org.apache.maven.api.services.ModelBuilderException;
47 import org.apache.maven.api.services.ModelBuilderRequest;
48 import org.apache.maven.api.services.ModelBuilderResult;
49 import org.apache.maven.api.services.ModelProblem;
50 import org.apache.maven.api.services.ModelResolver;
51 import org.apache.maven.api.services.ModelResolverException;
52 import org.apache.maven.api.services.ModelSource;
53 import org.apache.maven.api.services.ModelTransformerContext;
54 import org.apache.maven.api.services.ModelTransformerContextBuilder;
55 import org.apache.maven.api.services.Source;
56 import org.apache.maven.api.services.model.ModelBuildingListener;
57 import org.apache.maven.api.services.model.ModelProcessor;
58 import org.apache.maven.artifact.Artifact;
59 import org.apache.maven.artifact.InvalidArtifactRTException;
60 import org.apache.maven.artifact.InvalidRepositoryException;
61 import org.apache.maven.artifact.repository.ArtifactRepository;
62 import org.apache.maven.bridge.MavenRepositorySystem;
63 import org.apache.maven.internal.impl.InternalSession;
64 import org.apache.maven.model.building.ArtifactModelSource;
65 import org.apache.maven.model.building.DefaultModelProblem;
66 import org.apache.maven.model.building.FileModelSource;
67 import org.apache.maven.model.building.ModelSource2;
68 import org.apache.maven.model.building.ModelSource3;
69 import org.apache.maven.model.resolution.UnresolvableModelException;
70 import org.apache.maven.model.root.RootLocator;
71 import org.apache.maven.repository.internal.ArtifactDescriptorUtils;
72 import org.apache.maven.utils.Os;
73 import org.eclipse.aether.RepositorySystem;
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
87
88 @Named
89 @Singleton
90 public class DefaultProjectBuilder implements ProjectBuilder {
91 public static final String BUILDER_PARALLELISM = "maven.projectBuilder.parallelism";
92 public static final int DEFAULT_BUILDER_PARALLELISM = Runtime.getRuntime().availableProcessors() / 2 + 1;
93
94 private final Logger logger = LoggerFactory.getLogger(getClass());
95 private final ModelBuilder modelBuilder;
96 private final ModelProcessor modelProcessor;
97 private final ProjectBuildingHelper projectBuildingHelper;
98 private final MavenRepositorySystem repositorySystem;
99 private final org.eclipse.aether.RepositorySystem repoSystem;
100 private final RemoteRepositoryManager repositoryManager;
101 private final ProjectDependenciesResolver dependencyResolver;
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 RootLocator rootLocator) {
116 this.modelBuilder = modelBuilder;
117 this.modelProcessor = modelProcessor;
118 this.projectBuildingHelper = projectBuildingHelper;
119 this.repositorySystem = repositorySystem;
120 this.repoSystem = repoSystem;
121 this.repositoryManager = repositoryManager;
122 this.dependencyResolver = dependencyResolver;
123 this.rootLocator = rootLocator;
124 }
125
126
127
128
129 @Override
130 public ProjectBuildingResult build(File pomFile, ProjectBuildingRequest request) throws ProjectBuildingException {
131 try (BuildSession bs = new BuildSession(request, false)) {
132 Path path = pomFile.toPath();
133 return bs.build(path, ModelSource.fromPath(path));
134 }
135 }
136
137 @Deprecated
138 @Override
139 public ProjectBuildingResult build(
140 org.apache.maven.model.building.ModelSource modelSource, ProjectBuildingRequest request)
141 throws ProjectBuildingException {
142 return build(toSource(modelSource), request);
143 }
144
145 @Deprecated
146 private ModelSource toSource(org.apache.maven.model.building.ModelSource modelSource) {
147 if (modelSource instanceof FileModelSource fms) {
148 return ModelSource.fromPath(fms.getPath());
149 } else if (modelSource instanceof ArtifactModelSource ams) {
150 return ModelSource.fromPath(ams.getPath(), ams.toString());
151 } else {
152 return new ModelSource() {
153 @Override
154 public ModelSource resolve(ModelLocator modelLocator, String relative) {
155 if (modelSource instanceof ModelSource3 ms) {
156 return toSource(ms.getRelatedSource(
157 new org.apache.maven.model.locator.ModelLocator() {
158 @Override
159 public File locatePom(File projectDirectory) {
160 return null;
161 }
162
163 @Override
164 public Path locatePom(Path projectDirectory) {
165 return null;
166 }
167
168 @Override
169 public Path locateExistingPom(Path project) {
170 return modelLocator.locateExistingPom(project);
171 }
172 },
173 relative));
174 }
175 return null;
176 }
177
178 @Override
179 public Path getPath() {
180 return null;
181 }
182
183 @Override
184 public InputStream openStream() throws IOException {
185 return modelSource.getInputStream();
186 }
187
188 @Override
189 public String getLocation() {
190 return modelSource.getLocation();
191 }
192
193 @Override
194 public Source resolve(String relative) {
195 if (modelSource instanceof ModelSource2 ms) {
196 return toSource(ms.getRelatedSource(relative));
197 } else {
198 return null;
199 }
200 }
201 };
202 }
203 }
204
205 @Override
206 public ProjectBuildingResult build(ModelSource modelSource, ProjectBuildingRequest request)
207 throws ProjectBuildingException {
208 try (BuildSession bs = new BuildSession(request, false)) {
209 return bs.build(null, modelSource);
210 }
211 }
212
213 @Override
214 public ProjectBuildingResult build(Artifact artifact, ProjectBuildingRequest request)
215 throws ProjectBuildingException {
216 return build(artifact, false, request);
217 }
218
219 @Override
220 public ProjectBuildingResult build(Artifact artifact, boolean allowStubModel, ProjectBuildingRequest request)
221 throws ProjectBuildingException {
222 try (BuildSession bs = new BuildSession(request, false)) {
223 return bs.build(artifact, allowStubModel);
224 }
225 }
226
227 @Override
228 public List<ProjectBuildingResult> build(List<File> pomFiles, boolean recursive, ProjectBuildingRequest request)
229 throws ProjectBuildingException {
230 try (BuildSession bs = new BuildSession(request, true)) {
231 return bs.build(pomFiles, recursive);
232 }
233 }
234
235 static class InterimResult {
236
237 File pomFile;
238
239 ModelBuilderRequest request;
240
241 ModelBuilderResult result;
242
243 MavenProject project;
244
245 boolean root;
246
247 List<InterimResult> modules = Collections.emptyList();
248
249 ProjectBuildingResult projectBuildingResult;
250
251 InterimResult(
252 File pomFile,
253 ModelBuilderRequest request,
254 ModelBuilderResult result,
255 MavenProject project,
256 boolean root) {
257 this.pomFile = pomFile;
258 this.request = request;
259 this.result = result;
260 this.project = project;
261 this.root = root;
262 }
263
264 InterimResult(ModelBuilderRequest request, ProjectBuildingResult projectBuildingResult) {
265 this.request = request;
266 this.projectBuildingResult = projectBuildingResult;
267 this.pomFile = projectBuildingResult.getPomFile();
268 this.project = projectBuildingResult.getProject();
269 }
270 }
271
272 class BuildSession implements AutoCloseable {
273 private final ProjectBuildingRequest request;
274 private final RepositorySystemSession session;
275 private final List<RemoteRepository> repositories;
276 private final ReactorModelPool modelPool;
277 private final ConcurrentMap<String, Object> parentCache;
278 private final ModelTransformerContextBuilder transformerContextBuilder;
279 private final ExecutorService executor;
280
281 BuildSession(ProjectBuildingRequest request, boolean localProjects) {
282 this.request = request;
283 this.session =
284 RepositoryUtils.overlay(request.getLocalRepository(), request.getRepositorySession(), repoSystem);
285 InternalSession.from(session);
286 this.repositories = RepositoryUtils.toRepos(request.getRemoteRepositories());
287 this.executor = createExecutor(getParallelism(request));
288 if (localProjects) {
289 this.modelPool = new ReactorModelPool();
290 this.transformerContextBuilder = modelBuilder.newTransformerContextBuilder();
291 } else {
292 this.modelPool = null;
293 this.transformerContextBuilder = null;
294 }
295 this.parentCache = new ConcurrentHashMap<>();
296 }
297
298 ExecutorService createExecutor(int parallelism) {
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314 return new ThreadPoolExecutor(
315 parallelism, Integer.MAX_VALUE, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()) {
316 final AtomicInteger parked = new AtomicInteger();
317
318 @Override
319 public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
320 throws InterruptedException {
321 setCorePoolSize(parallelism + parked.incrementAndGet());
322 try {
323 return super.invokeAll(tasks);
324 } finally {
325 setCorePoolSize(parallelism + parked.decrementAndGet());
326 }
327 }
328 };
329 }
330
331 @Override
332 public void close() {
333 this.executor.shutdownNow();
334 }
335
336 private int getParallelism(ProjectBuildingRequest request) {
337 int parallelism = DEFAULT_BUILDER_PARALLELISM;
338 try {
339 String str = request.getUserProperties().getProperty(BUILDER_PARALLELISM);
340 if (str == null) {
341 str = request.getSystemProperties().getProperty(BUILDER_PARALLELISM);
342 }
343 if (str != null) {
344 parallelism = Integer.parseInt(str);
345 }
346 } catch (Exception e) {
347
348 }
349 return Math.max(1, Math.min(parallelism, Runtime.getRuntime().availableProcessors()));
350 }
351
352 ProjectBuildingResult build(Path pomFile, ModelSource modelSource) throws ProjectBuildingException {
353 ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
354
355 try {
356 MavenProject project = request.getProject();
357
358 List<ModelProblem> modelProblems = null;
359 Throwable error = null;
360
361 if (project == null) {
362 project = new MavenProject();
363 project.setFile(pomFile != null ? pomFile.toFile() : null);
364
365 ModelBuildingListener listener =
366 new DefaultModelBuildingListener(project, projectBuildingHelper, this.request);
367
368 ModelBuilderRequest.ModelBuilderRequestBuilder builder = getModelBuildingRequest();
369 ModelBuilderRequest request = builder.projectBuild(modelPool != null)
370 .source(modelSource)
371 .locationTracking(true)
372 .listener(listener)
373 .build();
374
375 if (pomFile != null) {
376 project.setRootDirectory(rootLocator.findRoot(pomFile.getParent()));
377 }
378
379 ModelBuilderResult result;
380 try {
381 result = modelBuilder.build(request);
382 } catch (ModelBuilderException e) {
383 result = e.getResult();
384 if (result == null || result.getEffectiveModel() == null) {
385 throw new ProjectBuildingException(
386 e.getModelId(), e.getMessage(), pomFile != null ? pomFile.toFile() : null, e);
387 }
388
389 error = e;
390 }
391
392 modelProblems = result.getProblems();
393
394 initProject(project, Collections.emptyMap(), result);
395 } else if (request.isResolveDependencies()) {
396 projectBuildingHelper.selectProjectRealm(project);
397 }
398
399 DependencyResolutionResult resolutionResult = null;
400
401 if (request.isResolveDependencies()) {
402 resolutionResult = resolveDependencies(project);
403 }
404
405 ProjectBuildingResult result =
406 new DefaultProjectBuildingResult(project, convert(modelProblems), resolutionResult);
407
408 if (error != null) {
409 ProjectBuildingException e = new ProjectBuildingException(List.of(result));
410 e.initCause(error);
411 throw e;
412 }
413
414 return result;
415 } finally {
416 Thread.currentThread().setContextClassLoader(oldContextClassLoader);
417 }
418 }
419
420 ProjectBuildingResult build(Artifact artifact, boolean allowStubModel) throws ProjectBuildingException {
421 org.eclipse.aether.artifact.Artifact pomArtifact = RepositoryUtils.toArtifact(artifact);
422 pomArtifact = ArtifactDescriptorUtils.toPomArtifact(pomArtifact);
423
424 boolean localProject;
425
426 try {
427 ArtifactRequest pomRequest = new ArtifactRequest();
428 pomRequest.setArtifact(pomArtifact);
429 pomRequest.setRepositories(repositories);
430 ArtifactResult pomResult = repoSystem.resolveArtifact(session, pomRequest);
431
432 pomArtifact = pomResult.getArtifact();
433 localProject = pomResult.getRepository() instanceof WorkspaceRepository;
434 } catch (org.eclipse.aether.resolution.ArtifactResolutionException e) {
435 if (e.getResults().get(0).isMissing() && allowStubModel) {
436 return build(null, createStubModelSource(artifact));
437 }
438 throw new ProjectBuildingException(
439 artifact.getId(), "Error resolving project artifact: " + e.getMessage(), e);
440 }
441
442 Path pomFile = pomArtifact.getPath();
443
444 if (!artifact.isResolved() && "pom".equals(artifact.getType())) {
445 artifact.selectVersion(pomArtifact.getVersion());
446 artifact.setFile(pomFile.toFile());
447 artifact.setResolved(true);
448 }
449
450 if (localProject) {
451 return build(pomFile, ModelSource.fromPath(pomFile));
452 } else {
453 return build(
454 null,
455 ModelSource.fromPath(
456 pomFile,
457 artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion()));
458 }
459 }
460
461 List<ProjectBuildingResult> build(List<File> pomFiles, boolean recursive) throws ProjectBuildingException {
462 List<ProjectBuildingResult> results = doBuild(pomFiles, recursive);
463 if (results.stream()
464 .flatMap(r -> r.getProblems().stream())
465 .anyMatch(p -> p.getSeverity() != org.apache.maven.model.building.ModelProblem.Severity.WARNING)) {
466 org.apache.maven.model.building.ModelProblem cycle = results.stream()
467 .flatMap(r -> r.getProblems().stream())
468 .filter(p -> p.getException() instanceof CycleDetectedException)
469 .findAny()
470 .orElse(null);
471 if (cycle != null) {
472 throw new RuntimeException(new ProjectCycleException(
473 "The projects in the reactor contain a cyclic reference: " + cycle.getMessage(),
474 (CycleDetectedException) cycle.getException()));
475 }
476 throw new ProjectBuildingException(results);
477 }
478
479 return results;
480 }
481
482 List<ProjectBuildingResult> doBuild(List<File> pomFiles, boolean recursive) {
483 Map<File, MavenProject> projectIndex = new ConcurrentHashMap<>(256);
484
485
486 List<InterimResult> interimResults = build(projectIndex, pomFiles, new LinkedHashSet<>(), true, recursive);
487
488 ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
489
490 try {
491
492 List<ProjectBuildingResult> results = build(projectIndex, interimResults);
493
494 if (Features.buildConsumer(request.getUserProperties())) {
495 request.getRepositorySession()
496 .getData()
497 .set(ModelTransformerContext.KEY, transformerContextBuilder.build());
498 }
499
500 return results;
501 } finally {
502 Thread.currentThread().setContextClassLoader(oldContextClassLoader);
503 }
504 }
505
506 @SuppressWarnings("checkstyle:parameternumber")
507 private List<InterimResult> build(
508 Map<File, MavenProject> projectIndex,
509 List<File> pomFiles,
510 Set<File> aggregatorFiles,
511 boolean root,
512 boolean recursive) {
513 List<Callable<InterimResult>> tasks = pomFiles.stream()
514 .map(pomFile -> ((Callable<InterimResult>)
515 () -> build(projectIndex, pomFile, concat(aggregatorFiles, pomFile), root, recursive)))
516 .collect(Collectors.toList());
517 try {
518 List<Future<InterimResult>> futures = executor.invokeAll(tasks);
519 List<InterimResult> list = new ArrayList<>();
520 for (Future<InterimResult> future : futures) {
521 InterimResult interimResult = future.get();
522 list.add(interimResult);
523 }
524 return list;
525 } catch (Exception e) {
526 throw new RuntimeException(e);
527 }
528 }
529
530 private <T> Set<T> concat(Set<T> set, T elem) {
531 Set<T> newSet = new HashSet<>(set);
532 newSet.add(elem);
533 return newSet;
534 }
535
536 @SuppressWarnings("checkstyle:parameternumber")
537 private InterimResult build(
538 Map<File, MavenProject> projectIndex,
539 File pomFile,
540 Set<File> aggregatorFiles,
541 boolean isRoot,
542 boolean recursive) {
543 MavenProject project = new MavenProject();
544 project.setFile(pomFile);
545
546 project.setRootDirectory(
547 rootLocator.findRoot(pomFile.getParentFile().toPath()));
548
549 DefaultModelBuildingListener listener =
550 new DefaultModelBuildingListener(project, projectBuildingHelper, request);
551
552 ModelBuilderRequest modelBuildingRequest = getModelBuildingRequest()
553 .source(ModelSource.fromPath(pomFile.toPath()))
554 .projectBuild(true)
555 .twoPhaseBuilding(true)
556 .locationTracking(true)
557 .listener(listener)
558 .build();
559
560 ModelBuilderResult result;
561 try {
562 result = modelBuilder.build(modelBuildingRequest);
563 } catch (ModelBuilderException e) {
564 result = e.getResult();
565 if (result == null || result.getFileModel() == null) {
566 return new InterimResult(
567 modelBuildingRequest,
568 new DefaultProjectBuildingResult(e.getModelId(), pomFile, convert(e.getProblems())));
569 }
570
571
572 }
573
574 Model model = result.getActivatedFileModel();
575
576 modelPool.put(model.getPomFile(), model);
577
578 InterimResult interimResult = new InterimResult(pomFile, modelBuildingRequest, result, project, isRoot);
579
580 if (recursive) {
581 File basedir = pomFile.getParentFile();
582 List<File> moduleFiles = new ArrayList<>();
583 for (String module : model.getModules()) {
584 if (module == null || module.isEmpty()) {
585 continue;
586 }
587
588 module = module.replace('\\', File.separatorChar).replace('/', File.separatorChar);
589
590 Path modulePath = modelProcessor.locateExistingPom(new File(basedir, module).toPath());
591 File moduleFile = modulePath != null ? modulePath.toFile() : null;
592
593 if (moduleFile == null) {
594 ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem(
595 "Child module " + moduleFile + " of " + pomFile + " does not exist",
596 ModelProblem.Severity.ERROR,
597 ModelProblem.Version.BASE,
598 model,
599 -1,
600 -1,
601 null);
602 result.getProblems().add(problem);
603 continue;
604 }
605
606 if (Os.IS_WINDOWS) {
607
608 try {
609 moduleFile = moduleFile.getCanonicalFile();
610 } catch (IOException e) {
611 moduleFile = moduleFile.getAbsoluteFile();
612 }
613 } else {
614 moduleFile = new File(moduleFile.toURI().normalize());
615 }
616
617 if (aggregatorFiles.contains(moduleFile)) {
618 StringBuilder buffer = new StringBuilder(256);
619 for (File aggregatorFile : aggregatorFiles) {
620 buffer.append(aggregatorFile).append(" -> ");
621 }
622 buffer.append(moduleFile);
623
624 ModelProblem problem = new org.apache.maven.internal.impl.model.DefaultModelProblem(
625 "Child module " + moduleFile + " of " + pomFile + " forms aggregation cycle " + buffer,
626 ModelProblem.Severity.ERROR,
627 ModelProblem.Version.BASE,
628 model,
629 -1,
630 -1,
631 null);
632 result.getProblems().add(problem);
633
634 continue;
635 }
636
637 moduleFiles.add(moduleFile);
638 }
639
640 if (!moduleFiles.isEmpty()) {
641 interimResult.modules = build(projectIndex, moduleFiles, aggregatorFiles, false, recursive);
642 }
643 }
644
645 projectIndex.put(pomFile, project);
646
647 return interimResult;
648 }
649
650 private List<ProjectBuildingResult> build(
651 Map<File, MavenProject> projectIndex, List<InterimResult> interimResults) {
652
653
654
655
656 List<ProjectBuildingResult> results = new ArrayList<>();
657 boolean failure = false;
658 for (InterimResult r : interimResults) {
659 DefaultProjectBuildingResult res;
660 try {
661 Model model = modelBuilder.buildRawModel(r.request);
662 res = new DefaultProjectBuildingResult(
663 model.getId(),
664 model.getPomFile() != null ? model.getPomFile().toFile() : null,
665 null);
666 } catch (ModelBuilderException e) {
667 failure = true;
668 res = new DefaultProjectBuildingResult(
669 e.getModelId(),
670 r.request.getSource().getPath() != null
671 ? r.request.getSource().getPath().toFile()
672 : null,
673 convert(e.getProblems()));
674 }
675 results.add(res);
676 }
677 if (failure) {
678 return results;
679 }
680
681 List<Callable<List<ProjectBuildingResult>>> callables = interimResults.stream()
682 .map(interimResult ->
683 (Callable<List<ProjectBuildingResult>>) () -> doBuild(projectIndex, interimResult))
684 .collect(Collectors.toList());
685
686 try {
687 List<Future<List<ProjectBuildingResult>>> futures = executor.invokeAll(callables);
688 return futures.stream()
689 .map(listFuture -> {
690 try {
691 return listFuture.get();
692 } catch (InterruptedException e) {
693 uncheckedThrow(e);
694 return null;
695 } catch (ExecutionException e) {
696 uncheckedThrow(e.getCause());
697 return null;
698 }
699 })
700 .flatMap(List::stream)
701 .collect(Collectors.toList());
702 } catch (InterruptedException e) {
703 uncheckedThrow(e);
704 return null;
705 }
706 }
707
708 private List<ProjectBuildingResult> doBuild(Map<File, MavenProject> projectIndex, InterimResult interimResult) {
709 if (interimResult.projectBuildingResult != null) {
710 return Collections.singletonList(interimResult.projectBuildingResult);
711 }
712 MavenProject project = interimResult.project;
713 try {
714 ModelBuilderResult result = modelBuilder.build(ModelBuilderRequest.builder(interimResult.request)
715 .interimResult(interimResult.result)
716 .build());
717
718
719 List<org.apache.maven.model.building.ModelProblem> problems = convert(result.getProblems());
720 try {
721 initProject(project, projectIndex, result);
722 } catch (InvalidArtifactRTException iarte) {
723 problems.add(new DefaultModelProblem(
724 null,
725 org.apache.maven.model.building.ModelProblem.Severity.ERROR,
726 null,
727 new org.apache.maven.model.Model(result.getEffectiveModel()),
728 -1,
729 -1,
730 iarte));
731 }
732
733 List<ProjectBuildingResult> results = build(projectIndex, interimResult.modules);
734
735 project.setExecutionRoot(interimResult.root);
736 project.setCollectedProjects(
737 results.stream().map(ProjectBuildingResult::getProject).collect(Collectors.toList()));
738 DependencyResolutionResult resolutionResult = null;
739 if (request.isResolveDependencies()) {
740 resolutionResult = resolveDependencies(project);
741 }
742
743 results.add(new DefaultProjectBuildingResult(project, problems, resolutionResult));
744
745 return results;
746 } catch (ModelBuilderException e) {
747 DefaultProjectBuildingResult result;
748 if (project == null || interimResult.result.getEffectiveModel() == null) {
749 result = new DefaultProjectBuildingResult(
750 e.getModelId(), interimResult.pomFile, convert(e.getProblems()));
751 } else {
752 project.setModel(new org.apache.maven.model.Model(interimResult.result.getEffectiveModel()));
753 result = new DefaultProjectBuildingResult(project, convert(e.getProblems()), null);
754 }
755 return Collections.singletonList(result);
756 }
757 }
758
759 private List<org.apache.maven.model.building.ModelProblem> convert(List<ModelProblem> problems) {
760 if (problems == null) {
761 return null;
762 }
763 return problems.stream()
764 .map(p -> (org.apache.maven.model.building.ModelProblem) new DefaultModelProblem(
765 p.getMessage(),
766 org.apache.maven.model.building.ModelProblem.Severity.valueOf(
767 p.getSeverity().name()),
768 org.apache.maven.model.building.ModelProblem.Version.valueOf(
769 p.getVersion().name()),
770 p.getSource(),
771 p.getLineNumber(),
772 p.getColumnNumber(),
773 p.getModelId(),
774 p.getException()))
775 .toList();
776 }
777
778 @SuppressWarnings({"checkstyle:methodlength", "deprecation"})
779 private void initProject(MavenProject project, Map<File, MavenProject> projects, ModelBuilderResult result) {
780 project.setModel(new org.apache.maven.model.Model(result.getEffectiveModel()));
781 project.setOriginalModel(new org.apache.maven.model.Model(result.getFileModel()));
782
783 initParent(project, projects, result);
784
785 Artifact projectArtifact = repositorySystem.createArtifact(
786 project.getGroupId(), project.getArtifactId(), project.getVersion(), null, project.getPackaging());
787 project.setArtifact(projectArtifact);
788
789
790 if (project.getFile() != null) {
791 Build build = project.getBuild().getDelegate();
792 project.addScriptSourceRoot(build.getScriptSourceDirectory());
793 project.addCompileSourceRoot(build.getSourceDirectory());
794 project.addTestCompileSourceRoot(build.getTestSourceDirectory());
795 }
796
797 project.setActiveProfiles(Stream.concat(
798 result.getActivePomProfiles(result.getModelIds().get(0)).stream(),
799 result.getActiveExternalProfiles().stream())
800 .map(org.apache.maven.model.Profile::new)
801 .toList());
802
803 project.setInjectedProfileIds("external", getProfileIds(result.getActiveExternalProfiles()));
804 for (String modelId : result.getModelIds()) {
805 project.setInjectedProfileIds(modelId, getProfileIds(result.getActivePomProfiles(modelId)));
806 }
807
808
809
810
811
812 project.setProjectBuildingRequest(request);
813
814
815 Set<Artifact> pluginArtifacts = new HashSet<>();
816 for (Plugin plugin : project.getModel().getDelegate().getBuild().getPlugins()) {
817 Artifact artifact = repositorySystem.createPluginArtifact(new org.apache.maven.model.Plugin(plugin));
818
819 if (artifact != null) {
820 pluginArtifacts.add(artifact);
821 }
822 }
823 project.setPluginArtifacts(pluginArtifacts);
824
825
826 Set<Artifact> reportArtifacts = new HashSet<>();
827 for (ReportPlugin report :
828 project.getModel().getDelegate().getReporting().getPlugins()) {
829 Plugin pp = Plugin.newBuilder()
830 .groupId(report.getGroupId())
831 .artifactId(report.getArtifactId())
832 .version(report.getVersion())
833 .build();
834
835 Artifact artifact = repositorySystem.createPluginArtifact(new org.apache.maven.model.Plugin(pp));
836
837 if (artifact != null) {
838 reportArtifacts.add(artifact);
839 }
840 }
841 project.setReportArtifacts(reportArtifacts);
842
843
844 Set<Artifact> extensionArtifacts = new HashSet<>();
845 List<Extension> extensions =
846 project.getModel().getDelegate().getBuild().getExtensions();
847 if (extensions != null) {
848 for (Extension ext : extensions) {
849 String version;
850 if (ext.getVersion() == null || ext.getVersion().isEmpty()) {
851 version = "RELEASE";
852 } else {
853 version = ext.getVersion();
854 }
855
856 Artifact artifact = repositorySystem.createArtifact(
857 ext.getGroupId(), ext.getArtifactId(), version, null, "jar");
858
859 if (artifact != null) {
860 extensionArtifacts.add(artifact);
861 }
862 }
863 }
864 project.setExtensionArtifacts(extensionArtifacts);
865
866
867 Map<String, Artifact> map = Collections.emptyMap();
868 final DependencyManagement dependencyManagement =
869 project.getModel().getDelegate().getDependencyManagement();
870 if (dependencyManagement != null
871 && dependencyManagement.getDependencies() != null
872 && !dependencyManagement.getDependencies().isEmpty()) {
873 map = new LazyMap<>(() -> {
874 Map<String, Artifact> tmp = new HashMap<>();
875 for (Dependency d : dependencyManagement.getDependencies()) {
876 Artifact artifact =
877 repositorySystem.createDependencyArtifact(new org.apache.maven.model.Dependency(d));
878 if (artifact != null) {
879 tmp.put(d.getManagementKey(), artifact);
880 }
881 }
882 return Collections.unmodifiableMap(tmp);
883 });
884 }
885 project.setManagedVersionMap(map);
886
887
888 if (project.getDistributionManagement() != null
889 && project.getDistributionManagement().getRepository() != null) {
890 try {
891 DeploymentRepository r = project.getModel()
892 .getDelegate()
893 .getDistributionManagement()
894 .getRepository();
895 if (r.getId() != null
896 && !r.getId().isEmpty()
897 && r.getUrl() != null
898 && !r.getUrl().isEmpty()) {
899 ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(
900 new org.apache.maven.model.DeploymentRepository(r));
901 repositorySystem.injectProxy(request.getRepositorySession(), List.of(repo));
902 repositorySystem.injectAuthentication(request.getRepositorySession(), List.of(repo));
903 project.setReleaseArtifactRepository(repo);
904 }
905 } catch (InvalidRepositoryException e) {
906 throw new IllegalStateException(
907 "Failed to create release distribution repository for " + project.getId(), e);
908 }
909 }
910
911
912 if (project.getDistributionManagement() != null
913 && project.getDistributionManagement().getSnapshotRepository() != null) {
914 try {
915 DeploymentRepository r = project.getModel()
916 .getDelegate()
917 .getDistributionManagement()
918 .getSnapshotRepository();
919 if (r.getId() != null
920 && !r.getId().isEmpty()
921 && r.getUrl() != null
922 && !r.getUrl().isEmpty()) {
923 ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(
924 new org.apache.maven.model.DeploymentRepository(r));
925 repositorySystem.injectProxy(request.getRepositorySession(), List.of(repo));
926 repositorySystem.injectAuthentication(request.getRepositorySession(), List.of(repo));
927 project.setSnapshotArtifactRepository(repo);
928 }
929 } catch (InvalidRepositoryException e) {
930 throw new IllegalStateException(
931 "Failed to create snapshot distribution repository for " + project.getId(), e);
932 }
933 }
934 }
935
936 private void initParent(MavenProject project, Map<File, MavenProject> projects, ModelBuilderResult result) {
937 Model parentModel = result.getModelIds().size() > 1
938 && !result.getModelIds().get(1).isEmpty()
939 ? result.getRawModel(result.getModelIds().get(1)).orElse(null)
940 : null;
941
942 if (parentModel != null) {
943 final String parentGroupId = inheritedGroupId(result, 1);
944 final String parentVersion = inheritedVersion(result, 1);
945
946 project.setParentArtifact(repositorySystem.createProjectArtifact(
947 parentGroupId, parentModel.getArtifactId(), parentVersion));
948
949
950 String parentModelId = result.getModelIds().get(1);
951 Path parentPomFile =
952 result.getRawModel(parentModelId).map(Model::getPomFile).orElse(null);
953 MavenProject parent = parentPomFile != null ? projects.get(parentPomFile.toFile()) : null;
954 if (parent == null) {
955
956
957
958
959
960 request.setRemoteRepositories(project.getRemoteArtifactRepositories());
961 if (parentPomFile != null) {
962 project.setParentFile(parentPomFile.toFile());
963 try {
964 parent = build(parentPomFile, ModelSource.fromPath(parentPomFile))
965 .getProject();
966 } catch (ProjectBuildingException e) {
967
968 if (logger.isDebugEnabled()) {
969
970 logger.warn("Failed to build parent project for " + project.getId(), e);
971 } else {
972
973 logger.warn("Failed to build parent project for " + project.getId());
974 }
975 }
976 } else {
977 Artifact parentArtifact = project.getParentArtifact();
978 try {
979 parent = build(parentArtifact, false).getProject();
980 } catch (ProjectBuildingException e) {
981
982 if (logger.isDebugEnabled()) {
983
984 logger.warn("Failed to build parent project for " + project.getId(), e);
985 } else {
986
987 logger.warn("Failed to build parent project for " + project.getId());
988 }
989 }
990 }
991 }
992 project.setParent(parent);
993 if (project.getParentFile() == null && parent != null) {
994 project.setParentFile(parent.getFile());
995 }
996 }
997 }
998
999 private ModelBuilderRequest.ModelBuilderRequestBuilder getModelBuildingRequest() {
1000 ModelBuilderRequest.ModelBuilderRequestBuilder modelBuildingRequest = ModelBuilderRequest.builder();
1001
1002 RequestTrace trace = RequestTrace.newChild(null, request).newChild(modelBuildingRequest);
1003
1004 ProjectModelResolver pmr = new ProjectModelResolver(
1005 session,
1006 trace,
1007 repoSystem,
1008 repositoryManager,
1009 repositories,
1010 request.getRepositoryMerging(),
1011 modelPool,
1012 parentCache);
1013 ModelResolver resolver = new ModelResolverWrapper(pmr);
1014
1015 modelBuildingRequest.session(InternalSession.from(session));
1016 modelBuildingRequest.validationLevel(request.getValidationLevel());
1017 modelBuildingRequest.processPlugins(request.isProcessPlugins());
1018 modelBuildingRequest.profiles(
1019 request.getProfiles() != null
1020 ? request.getProfiles().stream()
1021 .map(org.apache.maven.model.Profile::getDelegate)
1022 .toList()
1023 : null);
1024 modelBuildingRequest.activeProfileIds(request.getActiveProfileIds());
1025 modelBuildingRequest.inactiveProfileIds(request.getInactiveProfileIds());
1026 modelBuildingRequest.systemProperties(toMap(request.getSystemProperties()));
1027 modelBuildingRequest.userProperties(toMap(request.getUserProperties()));
1028
1029 modelBuildingRequest.modelResolver(resolver);
1030 modelBuildingRequest.transformerContextBuilder(transformerContextBuilder);
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043 return modelBuildingRequest;
1044 }
1045
1046 private DependencyResolutionResult resolveDependencies(MavenProject project) {
1047 DependencyResolutionResult resolutionResult;
1048
1049 try {
1050 DefaultDependencyResolutionRequest resolution =
1051 new DefaultDependencyResolutionRequest(project, session);
1052 resolutionResult = dependencyResolver.resolve(resolution);
1053 } catch (DependencyResolutionException e) {
1054 resolutionResult = e.getResult();
1055 }
1056
1057 Set<Artifact> artifacts = new LinkedHashSet<>();
1058 if (resolutionResult.getDependencyGraph() != null) {
1059 RepositoryUtils.toArtifacts(
1060 artifacts,
1061 resolutionResult.getDependencyGraph().getChildren(),
1062 Collections.singletonList(project.getArtifact().getId()),
1063 null);
1064
1065
1066 LocalRepositoryManager lrm = session.getLocalRepositoryManager();
1067 for (Artifact artifact : artifacts) {
1068 if (!artifact.isResolved()) {
1069 String path = lrm.getPathForLocalArtifact(RepositoryUtils.toArtifact(artifact));
1070 artifact.setFile(
1071 lrm.getRepository().getBasePath().resolve(path).toFile());
1072 }
1073 }
1074 }
1075 project.setResolvedArtifacts(artifacts);
1076 project.setArtifacts(artifacts);
1077
1078 return resolutionResult;
1079 }
1080 }
1081
1082 private List<String> getProfileIds(List<Profile> profiles) {
1083 return profiles.stream().map(Profile::getId).collect(Collectors.toList());
1084 }
1085
1086 private static ModelSource createStubModelSource(Artifact artifact) {
1087 StringBuilder buffer = new StringBuilder(1024);
1088
1089 buffer.append("<?xml version='1.0'?>");
1090 buffer.append("<project>");
1091 buffer.append("<modelVersion>4.0.0</modelVersion>");
1092 buffer.append("<groupId>").append(artifact.getGroupId()).append("</groupId>");
1093 buffer.append("<artifactId>").append(artifact.getArtifactId()).append("</artifactId>");
1094 buffer.append("<version>").append(artifact.getBaseVersion()).append("</version>");
1095 buffer.append("<packaging>").append(artifact.getType()).append("</packaging>");
1096 buffer.append("</project>");
1097
1098 return new ModelSource() {
1099 @Override
1100 public ModelSource resolve(ModelLocator modelLocator, String relative) {
1101 return null;
1102 }
1103
1104 @Override
1105 public Path getPath() {
1106 return null;
1107 }
1108
1109 @Override
1110 public InputStream openStream() throws IOException {
1111 return new ByteArrayInputStream(buffer.toString().getBytes(StandardCharsets.UTF_8));
1112 }
1113
1114 @Override
1115 public String getLocation() {
1116 return artifact.getId();
1117 }
1118
1119 @Override
1120 public Source resolve(String relative) {
1121 return null;
1122 }
1123 };
1124 }
1125
1126 private static String inheritedGroupId(final ModelBuilderResult result, final int modelIndex) {
1127 String groupId = null;
1128 final String modelId = result.getModelIds().get(modelIndex);
1129
1130 if (!modelId.isEmpty()) {
1131 final Model model = result.getRawModel(modelId).orElseThrow();
1132 groupId = model.getGroupId() != null ? model.getGroupId() : inheritedGroupId(result, modelIndex + 1);
1133 }
1134
1135 return groupId;
1136 }
1137
1138 private static String inheritedVersion(final ModelBuilderResult result, final int modelIndex) {
1139 String version = null;
1140 final String modelId = result.getModelIds().get(modelIndex);
1141
1142 if (!modelId.isEmpty()) {
1143 version = result.getRawModel(modelId).map(Model::getVersion).orElse(null);
1144 if (version == null) {
1145 version = inheritedVersion(result, modelIndex + 1);
1146 }
1147 }
1148
1149 return version;
1150 }
1151
1152 private static Map<String, String> toMap(Properties properties) {
1153 if (properties != null && !properties.isEmpty()) {
1154 return properties.entrySet().stream()
1155 .collect(Collectors.toMap(e -> String.valueOf(e.getKey()), e -> String.valueOf(e.getValue())));
1156
1157 } else {
1158 return null;
1159 }
1160 }
1161
1162 @SuppressWarnings("unchecked")
1163 static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
1164 throw (T) t;
1165 }
1166
1167 static class LazyMap<K, V> extends AbstractMap<K, V> {
1168 private final Supplier<Map<K, V>> supplier;
1169 private volatile Map<K, V> delegate;
1170
1171 LazyMap(Supplier<Map<K, V>> supplier) {
1172 this.supplier = supplier;
1173 }
1174
1175 @Override
1176 public Set<Entry<K, V>> entrySet() {
1177 if (delegate == null) {
1178 synchronized (this) {
1179 if (delegate == null) {
1180 delegate = supplier.get();
1181 }
1182 }
1183 }
1184 return delegate.entrySet();
1185 }
1186 }
1187
1188 protected class ModelResolverWrapper implements ModelResolver {
1189 protected final org.apache.maven.model.resolution.ModelResolver resolver;
1190
1191 protected ModelResolverWrapper(org.apache.maven.model.resolution.ModelResolver resolver) {
1192 this.resolver = resolver;
1193 }
1194
1195 @Override
1196 public ModelSource resolveModel(Session session, String groupId, String artifactId, String version)
1197 throws ModelResolverException {
1198 try {
1199 return toSource(resolver.resolveModel(groupId, artifactId, version));
1200 } catch (UnresolvableModelException e) {
1201 throw new ModelResolverException(e.getMessage(), e.getGroupId(), e.getArtifactId(), e.getVersion(), e);
1202 }
1203 }
1204
1205 @Override
1206 public ModelSource resolveModel(Session session, Parent parent, AtomicReference<Parent> modified)
1207 throws ModelResolverException {
1208 try {
1209 org.apache.maven.model.Parent p = new org.apache.maven.model.Parent(parent);
1210 ModelSource source = toSource(resolver.resolveModel(p));
1211 if (p.getDelegate() != parent) {
1212 modified.set(p.getDelegate());
1213 }
1214 return source;
1215 } catch (UnresolvableModelException e) {
1216 throw new ModelResolverException(e.getMessage(), e.getGroupId(), e.getArtifactId(), e.getVersion(), e);
1217 }
1218 }
1219
1220 @Override
1221 public ModelSource resolveModel(Session session, Dependency dependency, AtomicReference<Dependency> modified)
1222 throws ModelResolverException {
1223 try {
1224 org.apache.maven.model.Dependency d = new org.apache.maven.model.Dependency(dependency);
1225 ModelSource source = toSource(resolver.resolveModel(d));
1226 if (d.getDelegate() != dependency) {
1227 modified.set(d.getDelegate());
1228 }
1229 return source;
1230 } catch (UnresolvableModelException e) {
1231 throw new ModelResolverException(e.getMessage(), e.getGroupId(), e.getArtifactId(), e.getVersion(), e);
1232 }
1233 }
1234
1235 @Override
1236 public void addRepository(Session session, Repository repository) throws ModelResolverException {
1237 addRepository(session, repository, false);
1238 }
1239
1240 @Override
1241 public void addRepository(Session session, Repository repository, boolean replace)
1242 throws ModelResolverException {
1243 try {
1244 resolver.addRepository(new org.apache.maven.model.Repository(repository), replace);
1245 } catch (org.apache.maven.model.resolution.InvalidRepositoryException e) {
1246 throw new MavenException(e);
1247 }
1248 }
1249
1250 @Override
1251 public ModelResolver newCopy() {
1252 return new ModelResolverWrapper(resolver.newCopy());
1253 }
1254 }
1255 }