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