1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.internal.impl.model;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.lang.reflect.Field;
24 import java.nio.file.Files;
25 import java.nio.file.Path;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.LinkedHashSet;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Objects;
34 import java.util.Properties;
35 import java.util.concurrent.Callable;
36 import java.util.concurrent.atomic.AtomicReference;
37 import java.util.function.BiConsumer;
38 import java.util.function.Supplier;
39 import java.util.function.UnaryOperator;
40 import java.util.stream.Collectors;
41 import java.util.stream.Stream;
42
43 import org.apache.maven.api.Session;
44 import org.apache.maven.api.Type;
45 import org.apache.maven.api.VersionRange;
46 import org.apache.maven.api.annotations.Nullable;
47 import org.apache.maven.api.di.Inject;
48 import org.apache.maven.api.di.Named;
49 import org.apache.maven.api.di.Singleton;
50 import org.apache.maven.api.feature.Features;
51 import org.apache.maven.api.model.Activation;
52 import org.apache.maven.api.model.ActivationFile;
53 import org.apache.maven.api.model.Build;
54 import org.apache.maven.api.model.Dependency;
55 import org.apache.maven.api.model.DependencyManagement;
56 import org.apache.maven.api.model.Exclusion;
57 import org.apache.maven.api.model.InputLocation;
58 import org.apache.maven.api.model.InputLocationTracker;
59 import org.apache.maven.api.model.InputSource;
60 import org.apache.maven.api.model.Model;
61 import org.apache.maven.api.model.Parent;
62 import org.apache.maven.api.model.Plugin;
63 import org.apache.maven.api.model.PluginManagement;
64 import org.apache.maven.api.model.Profile;
65 import org.apache.maven.api.services.BuilderProblem.Severity;
66 import org.apache.maven.api.services.ModelBuilder;
67 import org.apache.maven.api.services.ModelBuilderException;
68 import org.apache.maven.api.services.ModelBuilderRequest;
69 import org.apache.maven.api.services.ModelBuilderResult;
70 import org.apache.maven.api.services.ModelCache;
71 import org.apache.maven.api.services.ModelProblem;
72 import org.apache.maven.api.services.ModelProblemCollector;
73 import org.apache.maven.api.services.ModelResolver;
74 import org.apache.maven.api.services.ModelResolverException;
75 import org.apache.maven.api.services.ModelSource;
76 import org.apache.maven.api.services.ModelTransformer;
77 import org.apache.maven.api.services.ModelTransformerContext;
78 import org.apache.maven.api.services.ModelTransformerContextBuilder;
79 import org.apache.maven.api.services.ModelTransformerException;
80 import org.apache.maven.api.services.Source;
81 import org.apache.maven.api.services.SuperPomProvider;
82 import org.apache.maven.api.services.VersionParserException;
83 import org.apache.maven.api.services.model.DependencyManagementImporter;
84 import org.apache.maven.api.services.model.DependencyManagementInjector;
85 import org.apache.maven.api.services.model.InheritanceAssembler;
86 import org.apache.maven.api.services.model.LifecycleBindingsInjector;
87 import org.apache.maven.api.services.model.ModelBuildingEvent;
88 import org.apache.maven.api.services.model.ModelBuildingListener;
89 import org.apache.maven.api.services.model.ModelInterpolator;
90 import org.apache.maven.api.services.model.ModelNormalizer;
91 import org.apache.maven.api.services.model.ModelPathTranslator;
92 import org.apache.maven.api.services.model.ModelProcessor;
93 import org.apache.maven.api.services.model.ModelUrlNormalizer;
94 import org.apache.maven.api.services.model.ModelValidator;
95 import org.apache.maven.api.services.model.ModelVersionParser;
96 import org.apache.maven.api.services.model.PluginConfigurationExpander;
97 import org.apache.maven.api.services.model.PluginManagementInjector;
98 import org.apache.maven.api.services.model.ProfileActivationContext;
99 import org.apache.maven.api.services.model.ProfileInjector;
100 import org.apache.maven.api.services.model.ProfileSelector;
101 import org.apache.maven.api.services.model.WorkspaceModelResolver;
102 import org.apache.maven.api.services.xml.XmlReaderException;
103 import org.apache.maven.api.services.xml.XmlReaderRequest;
104 import org.apache.maven.internal.impl.resolver.DefaultModelCache;
105 import org.apache.maven.internal.impl.resolver.DefaultModelRepositoryHolder;
106 import org.apache.maven.internal.impl.resolver.DefaultModelResolver;
107 import org.apache.maven.model.v4.MavenTransformer;
108 import org.codehaus.plexus.interpolation.InterpolationException;
109 import org.codehaus.plexus.interpolation.Interpolator;
110 import org.codehaus.plexus.interpolation.MapBasedValueSource;
111 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
112 import org.codehaus.plexus.interpolation.StringSearchInterpolator;
113 import org.slf4j.Logger;
114 import org.slf4j.LoggerFactory;
115
116
117
118 @Named
119 @Singleton
120 public class DefaultModelBuilder implements ModelBuilder {
121
122 public static final String NAMESPACE_PREFIX = "http://maven.apache.org/POM/";
123 private static final String RAW = "raw";
124 private static final String FILE = "file";
125 private static final String IMPORT = "import";
126
127 private final Logger logger = LoggerFactory.getLogger(getClass());
128
129 private final ModelProcessor modelProcessor;
130 private final ModelValidator modelValidator;
131 private final ModelNormalizer modelNormalizer;
132 private final ModelInterpolator modelInterpolator;
133 private final ModelPathTranslator modelPathTranslator;
134 private final ModelUrlNormalizer modelUrlNormalizer;
135 private final SuperPomProvider superPomProvider;
136 private final InheritanceAssembler inheritanceAssembler;
137 private final ProfileSelector profileSelector;
138 private final ProfileInjector profileInjector;
139 private final PluginManagementInjector pluginManagementInjector;
140 private final DependencyManagementInjector dependencyManagementInjector;
141 private final DependencyManagementImporter dependencyManagementImporter;
142 private final LifecycleBindingsInjector lifecycleBindingsInjector;
143 private final PluginConfigurationExpander pluginConfigurationExpander;
144 private final ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator;
145 private final ModelTransformer transformer;
146 private final ModelVersionParser versionParser;
147
148 @SuppressWarnings("checkstyle:ParameterNumber")
149 @Inject
150 public DefaultModelBuilder(
151 ModelProcessor modelProcessor,
152 ModelValidator modelValidator,
153 ModelNormalizer modelNormalizer,
154 ModelInterpolator modelInterpolator,
155 ModelPathTranslator modelPathTranslator,
156 ModelUrlNormalizer modelUrlNormalizer,
157 SuperPomProvider superPomProvider,
158 InheritanceAssembler inheritanceAssembler,
159 ProfileSelector profileSelector,
160 ProfileInjector profileInjector,
161 PluginManagementInjector pluginManagementInjector,
162 DependencyManagementInjector dependencyManagementInjector,
163 DependencyManagementImporter dependencyManagementImporter,
164 @Nullable LifecycleBindingsInjector lifecycleBindingsInjector,
165 PluginConfigurationExpander pluginConfigurationExpander,
166 ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator,
167 ModelTransformer transformer,
168 ModelVersionParser versionParser) {
169 this.modelProcessor = modelProcessor;
170 this.modelValidator = modelValidator;
171 this.modelNormalizer = modelNormalizer;
172 this.modelInterpolator = modelInterpolator;
173 this.modelPathTranslator = modelPathTranslator;
174 this.modelUrlNormalizer = modelUrlNormalizer;
175 this.superPomProvider = superPomProvider;
176 this.inheritanceAssembler = inheritanceAssembler;
177 this.profileSelector = profileSelector;
178 this.profileInjector = profileInjector;
179 this.pluginManagementInjector = pluginManagementInjector;
180 this.dependencyManagementInjector = dependencyManagementInjector;
181 this.dependencyManagementImporter = dependencyManagementImporter;
182 this.lifecycleBindingsInjector = lifecycleBindingsInjector;
183 this.pluginConfigurationExpander = pluginConfigurationExpander;
184 this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator;
185 this.transformer = transformer;
186 this.versionParser = versionParser;
187 }
188
189 @Override
190 public ModelTransformerContextBuilder newTransformerContextBuilder() {
191 return new DefaultModelTransformerContextBuilder(this);
192 }
193
194 @Override
195 public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilderException {
196 request = fillRequestDefaults(request);
197 if (request.getInterimResult() != null) {
198 return build(request, request.getInterimResult(), new LinkedHashSet<>());
199 } else {
200 return build(request, new LinkedHashSet<>());
201 }
202 }
203
204 private static ModelBuilderRequest fillRequestDefaults(ModelBuilderRequest request) {
205 ModelBuilderRequest.ModelBuilderRequestBuilder builder = ModelBuilderRequest.builder(request);
206 if (request.getModelCache() == null) {
207 builder.modelCache(new DefaultModelCache());
208 }
209 if (request.getModelRepositoryHolder() == null) {
210 builder.modelRepositoryHolder(new DefaultModelRepositoryHolder(
211 request.getSession(),
212 DefaultModelRepositoryHolder.RepositoryMerging.POM_DOMINANT,
213 request.getSession().getRemoteRepositories()));
214 }
215 if (request.getModelResolver() == null) {
216 builder.modelResolver(new DefaultModelResolver());
217 }
218 return builder.build();
219 }
220
221 protected ModelBuilderResult build(ModelBuilderRequest request, Collection<String> importIds)
222 throws ModelBuilderException {
223
224 DefaultModelBuilderResult result = new DefaultModelBuilderResult();
225
226 DefaultModelProblemCollector problems = new DefaultModelProblemCollector(result);
227
228
229 Model fileModel = readFileModel(request, problems);
230 result.setFileModel(fileModel);
231
232 Model activatedFileModel = activateFileModel(fileModel, request, result, problems);
233 result.setActivatedFileModel(activatedFileModel);
234
235 if (!request.isTwoPhaseBuilding()) {
236 return build(request, result, importIds);
237 } else if (hasModelErrors(problems)) {
238 throw problems.newModelBuilderException();
239 }
240
241 return result;
242 }
243
244 private Model activateFileModel(
245 Model inputModel,
246 ModelBuilderRequest request,
247 DefaultModelBuilderResult result,
248 DefaultModelProblemCollector problems)
249 throws ModelBuilderException {
250 problems.setRootModel(inputModel);
251
252
253 DefaultProfileActivationContext profileActivationContext = getProfileActivationContext(request, inputModel);
254
255 problems.setSource("(external profiles)");
256 List<Profile> activeExternalProfiles =
257 profileSelector.getActiveProfiles(request.getProfiles(), profileActivationContext, problems);
258
259 result.setActiveExternalProfiles(activeExternalProfiles);
260
261 if (!activeExternalProfiles.isEmpty()) {
262 Properties profileProps = new Properties();
263 for (Profile profile : activeExternalProfiles) {
264 profileProps.putAll(profile.getProperties());
265 }
266 profileProps.putAll(profileActivationContext.getUserProperties());
267 profileActivationContext.setUserProperties(profileProps);
268 }
269
270 profileActivationContext.setProjectProperties(inputModel.getProperties());
271 problems.setSource(inputModel);
272 List<Profile> activePomProfiles =
273 profileSelector.getActiveProfiles(inputModel.getProfiles(), profileActivationContext, problems);
274
275
276 problems.setSource(inputModel);
277 inputModel = modelNormalizer.mergeDuplicates(inputModel, request, problems);
278
279 Map<String, Activation> interpolatedActivations = getProfileActivations(inputModel);
280 inputModel = injectProfileActivations(inputModel, interpolatedActivations);
281
282
283 inputModel = profileInjector.injectProfiles(inputModel, activePomProfiles, request, problems);
284 inputModel = profileInjector.injectProfiles(inputModel, activeExternalProfiles, request, problems);
285
286 return inputModel;
287 }
288
289 @SuppressWarnings("checkstyle:methodlength")
290 private Model readEffectiveModel(
291 final ModelBuilderRequest request,
292 final DefaultModelBuilderResult result,
293 DefaultModelProblemCollector problems)
294 throws ModelBuilderException {
295 Model inputModel = readRawModel(request, problems);
296 if (problems.hasFatalErrors()) {
297 throw problems.newModelBuilderException();
298 }
299
300 inputModel = activateFileModel(inputModel, request, result, problems);
301
302 problems.setRootModel(inputModel);
303
304 ModelData resultData = new ModelData(request.getSource(), inputModel);
305 String superModelVersion = inputModel.getModelVersion() != null ? inputModel.getModelVersion() : "4.0.0";
306 if (!VALID_MODEL_VERSIONS.contains(superModelVersion)) {
307
308
309
310 superModelVersion = MODEL_VERSION_4_0_0;
311 }
312 ModelData superData = new ModelData(null, getSuperModel(superModelVersion));
313
314
315 DefaultProfileActivationContext profileActivationContext = getProfileActivationContext(request, inputModel);
316
317 List<Profile> activeExternalProfiles = result.getActiveExternalProfiles();
318
319 if (!activeExternalProfiles.isEmpty()) {
320 Properties profileProps = new Properties();
321 for (Profile profile : activeExternalProfiles) {
322 profileProps.putAll(profile.getProperties());
323 }
324 profileProps.putAll(profileActivationContext.getUserProperties());
325 profileActivationContext.setUserProperties(profileProps);
326 }
327
328 Collection<String> parentIds = new LinkedHashSet<>();
329
330 List<Model> lineage = new ArrayList<>();
331
332 for (ModelData currentData = resultData; ; ) {
333 String modelId = currentData.id();
334 result.addModelId(modelId);
335
336 Model model = currentData.model();
337 result.setRawModel(modelId, model);
338 problems.setSource(model);
339
340
341 model = modelNormalizer.mergeDuplicates(model, request, problems);
342
343
344 profileActivationContext.setProjectProperties(model.getProperties());
345
346 List<Profile> interpolatedProfiles =
347 interpolateActivations(model.getProfiles(), profileActivationContext, problems);
348
349
350 List<Profile> activePomProfiles =
351 profileSelector.getActiveProfiles(interpolatedProfiles, profileActivationContext, problems);
352 result.setActivePomProfiles(modelId, activePomProfiles);
353 model = profileInjector.injectProfiles(model, activePomProfiles, request, problems);
354 if (currentData == resultData) {
355 model = profileInjector.injectProfiles(model, activeExternalProfiles, request, problems);
356 }
357
358 lineage.add(model);
359
360 if (currentData == superData) {
361 break;
362 }
363
364
365 if (!model.getRepositories().isEmpty()) {
366 List<String> oldRepos = request.getModelRepositoryHolder().getRepositories().stream()
367 .map(Object::toString)
368 .toList();
369 request.getModelRepositoryHolder().merge(model.getRepositories(), false);
370 List<String> newRepos = request.getModelRepositoryHolder().getRepositories().stream()
371 .map(Object::toString)
372 .toList();
373 if (!Objects.equals(oldRepos, newRepos)) {
374 logger.debug("Merging repositories from " + model.getId() + "\n"
375 + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n")));
376 }
377 }
378
379
380 ModelData parentData = readParent(model, currentData.source(), request, problems);
381
382 if (parentData == null) {
383 currentData = superData;
384 } else if (!parentIds.add(parentData.id())) {
385 StringBuilder message = new StringBuilder("The parents form a cycle: ");
386 for (String parentId : parentIds) {
387 message.append(parentId).append(" -> ");
388 }
389 message.append(parentData.id());
390
391 problems.add(Severity.FATAL, ModelProblem.Version.BASE, message.toString());
392
393 throw problems.newModelBuilderException();
394 } else {
395 currentData = parentData;
396 }
397 }
398
399 Model tmpModel = lineage.get(0);
400
401
402 List<Profile> interpolated = interpolateActivations(tmpModel.getProfiles(), profileActivationContext, problems);
403 if (interpolated != tmpModel.getProfiles()) {
404 tmpModel = tmpModel.withProfiles(interpolated);
405 }
406
407
408 tmpModel = profileInjector.injectProfiles(tmpModel, activeExternalProfiles, request, problems);
409
410 lineage.set(0, tmpModel);
411
412 checkPluginVersions(lineage, request, problems);
413
414
415 Model resultModel = assembleInheritance(lineage, request, problems);
416
417
418
419 problems.setSource(resultModel);
420 problems.setRootModel(resultModel);
421
422
423 resultModel = interpolateModel(resultModel, request, problems);
424
425
426 resultModel = modelUrlNormalizer.normalize(resultModel, request);
427
428 result.setEffectiveModel(resultModel);
429
430
431 if (!resultModel.getRepositories().isEmpty()) {
432 List<String> oldRepos = request.getModelRepositoryHolder().getRepositories().stream()
433 .map(Object::toString)
434 .toList();
435 request.getModelRepositoryHolder().merge(resultModel.getRepositories(), true);
436 List<String> newRepos = request.getModelRepositoryHolder().getRepositories().stream()
437 .map(Object::toString)
438 .toList();
439 if (!Objects.equals(oldRepos, newRepos)) {
440 logger.debug("Replacing repositories from " + resultModel.getId() + "\n"
441 + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n")));
442 }
443 }
444
445 return resultModel;
446 }
447
448 private List<Profile> interpolateActivations(
449 List<Profile> profiles, DefaultProfileActivationContext context, DefaultModelProblemCollector problems) {
450 if (profiles.stream()
451 .map(org.apache.maven.api.model.Profile::getActivation)
452 .noneMatch(Objects::nonNull)) {
453 return profiles;
454 }
455 final Interpolator xform = new RegexBasedInterpolator();
456 xform.setCacheAnswers(true);
457 Stream.of(context.getUserProperties(), context.getSystemProperties())
458 .map(MapBasedValueSource::new)
459 .forEach(xform::addValueSource);
460
461 class ProfileInterpolator extends MavenTransformer implements UnaryOperator<Profile> {
462 ProfileInterpolator() {
463 super(s -> {
464 if (isNotEmpty(s)) {
465 try {
466 return xform.interpolate(s);
467 } catch (InterpolationException e) {
468 problems.add(Severity.ERROR, ModelProblem.Version.BASE, e.getMessage(), e);
469 }
470 }
471 return s;
472 });
473 }
474
475 @Override
476 public Profile apply(Profile p) {
477 return Profile.newBuilder(p)
478 .activation(transformActivation(p.getActivation()))
479 .build();
480 }
481
482 @Override
483 protected ActivationFile.Builder transformActivationFile_Missing(
484 Supplier<? extends ActivationFile.Builder> creator,
485 ActivationFile.Builder builder,
486 ActivationFile target) {
487 String path = target.getMissing();
488 String xformed = transformPath(path, target, "missing");
489 return xformed != path ? (builder != null ? builder : creator.get()).missing(xformed) : builder;
490 }
491
492 @Override
493 protected ActivationFile.Builder transformActivationFile_Exists(
494 Supplier<? extends ActivationFile.Builder> creator,
495 ActivationFile.Builder builder,
496 ActivationFile target) {
497 final String path = target.getExists();
498 final String xformed = transformPath(path, target, "exists");
499 return xformed != path ? (builder != null ? builder : creator.get()).exists(xformed) : builder;
500 }
501
502 private String transformPath(String path, ActivationFile target, String locationKey) {
503 if (isNotEmpty(path)) {
504 try {
505 return profileActivationFilePathInterpolator.interpolate(path, context);
506 } catch (InterpolationException e) {
507 addInterpolationProblem(problems, target, path, e, locationKey);
508 }
509 }
510 return path;
511 }
512 }
513 return profiles.stream().map(new ProfileInterpolator()).toList();
514 }
515
516 private static void addInterpolationProblem(
517 DefaultModelProblemCollector problems,
518 InputLocationTracker target,
519 String path,
520 InterpolationException e,
521 String locationKey) {
522 problems.add(
523 Severity.ERROR,
524 ModelProblem.Version.BASE,
525 "Failed to interpolate file location " + path + ": " + e.getMessage(),
526 target.getLocation(locationKey),
527 e);
528 }
529
530 private static boolean isNotEmpty(String string) {
531 return string != null && !string.isEmpty();
532 }
533
534 public ModelBuilderResult build(final ModelBuilderRequest request, final ModelBuilderResult result)
535 throws ModelBuilderException {
536 return build(request, result, new LinkedHashSet<>());
537 }
538
539 public Model buildRawModel(ModelBuilderRequest request) throws ModelBuilderException {
540 request = fillRequestDefaults(request);
541 DefaultModelProblemCollector problems = new DefaultModelProblemCollector(new DefaultModelBuilderResult());
542 Model model = readRawModel(request, problems);
543 if (hasModelErrors(problems)) {
544 throw problems.newModelBuilderException();
545 }
546 return model;
547 }
548
549 private ModelBuilderResult build(
550 ModelBuilderRequest request, final ModelBuilderResult phaseOneResult, Collection<String> importIds)
551 throws ModelBuilderException {
552 DefaultModelBuilderResult result = asDefaultModelBuilderResult(phaseOneResult);
553
554 DefaultModelProblemCollector problems = new DefaultModelProblemCollector(result);
555
556
557 Model resultModel = readEffectiveModel(request, result, problems);
558 problems.setSource(resultModel);
559 problems.setRootModel(resultModel);
560
561
562 resultModel = modelPathTranslator.alignToBaseDirectory(resultModel, resultModel.getProjectDirectory(), request);
563
564
565 resultModel = pluginManagementInjector.injectManagement(resultModel, request, problems);
566
567 resultModel = fireEvent(resultModel, request, problems, ModelBuildingListener::buildExtensionsAssembled);
568
569 if (request.isProcessPlugins()) {
570 if (lifecycleBindingsInjector == null) {
571 throw new IllegalStateException("lifecycle bindings injector is missing");
572 }
573
574
575 resultModel = lifecycleBindingsInjector.injectLifecycleBindings(resultModel, request, problems);
576 }
577
578
579 resultModel = importDependencyManagement(resultModel, request, problems, importIds);
580
581
582 resultModel = dependencyManagementInjector.injectManagement(resultModel, request, problems);
583
584 resultModel = modelNormalizer.injectDefaultValues(resultModel, request, problems);
585
586 if (request.isProcessPlugins()) {
587
588 resultModel = pluginConfigurationExpander.expandPluginConfiguration(resultModel, request, problems);
589 }
590
591 result.setEffectiveModel(resultModel);
592
593
594 modelValidator.validateEffectiveModel(resultModel, request, problems);
595
596 if (hasModelErrors(problems)) {
597 throw problems.newModelBuilderException();
598 }
599
600 return result;
601 }
602
603 private DefaultModelBuilderResult asDefaultModelBuilderResult(ModelBuilderResult phaseOneResult) {
604 if (phaseOneResult instanceof DefaultModelBuilderResult) {
605 return (DefaultModelBuilderResult) phaseOneResult;
606 } else {
607 return new DefaultModelBuilderResult(phaseOneResult);
608 }
609 }
610
611 public Result<? extends Model> buildRawModel(Path pomFile, int validationLevel, boolean locationTracking) {
612 return buildRawModel(pomFile, validationLevel, locationTracking, null);
613 }
614
615 public Result<? extends Model> buildRawModel(
616 Path pomFile, int validationLevel, boolean locationTracking, ModelTransformerContext context) {
617 final ModelBuilderRequest request = ModelBuilderRequest.builder()
618 .validationLevel(validationLevel)
619 .locationTracking(locationTracking)
620 .source(ModelSource.fromPath(pomFile))
621 .build();
622 DefaultModelProblemCollector problems = new DefaultModelProblemCollector(new DefaultModelBuilderResult());
623 try {
624 Model model = readFileModel(request, problems);
625
626 try {
627 if (transformer != null && context != null) {
628 transformer.transform(context, model, pomFile);
629 }
630 } catch (ModelBuilderException e) {
631 problems.add(Severity.FATAL, ModelProblem.Version.V40, null, e);
632 }
633
634 return Result.newResult(model, problems.getProblems());
635 } catch (ModelBuilderException e) {
636 return Result.error(problems.getProblems());
637 }
638 }
639
640 Model readFileModel(ModelBuilderRequest request, DefaultModelProblemCollector problems)
641 throws ModelBuilderException {
642 ModelSource modelSource = request.getSource();
643 Model model =
644 cache(getModelCache(request), modelSource, FILE, () -> doReadFileModel(modelSource, request, problems));
645
646 if (modelSource.getPath() != null) {
647 if (getTransformerContextBuilder(request) instanceof DefaultModelTransformerContextBuilder contextBuilder) {
648 contextBuilder.putSource(getGroupId(model), model.getArtifactId(), modelSource);
649 }
650 }
651
652 return model;
653 }
654
655 @SuppressWarnings("checkstyle:methodlength")
656 private Model doReadFileModel(
657 ModelSource modelSource, ModelBuilderRequest request, DefaultModelProblemCollector problems)
658 throws ModelBuilderException {
659 Model model;
660 problems.setSource(modelSource.getLocation());
661 try {
662 boolean strict = request.getValidationLevel() >= ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_2_0;
663
664 Path rootDirectory;
665 try {
666 rootDirectory = request.getSession().getRootDirectory();
667 } catch (IllegalStateException ignore) {
668 rootDirectory = modelSource.getPath();
669 }
670 try (InputStream is = modelSource.openStream()) {
671 model = modelProcessor.read(XmlReaderRequest.builder()
672 .strict(strict)
673 .location(modelSource.getLocation())
674 .path(modelSource.getPath())
675 .rootDirectory(rootDirectory)
676 .inputStream(is)
677 .build());
678 } catch (XmlReaderException e) {
679 if (!strict) {
680 throw e;
681 }
682 try (InputStream is = modelSource.openStream()) {
683 model = modelProcessor.read(XmlReaderRequest.builder()
684 .strict(false)
685 .location(modelSource.getLocation())
686 .path(modelSource.getPath())
687 .rootDirectory(rootDirectory)
688 .inputStream(is)
689 .build());
690 } catch (XmlReaderException ne) {
691
692 throw e;
693 }
694
695 Severity severity = request.isProjectBuild() ? Severity.ERROR : Severity.WARNING;
696 problems.add(
697 severity,
698 ModelProblem.Version.V20,
699 "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage(),
700 e);
701 }
702
703 InputLocation loc = model.getLocation("");
704 InputSource v4src = loc != null ? loc.getSource() : null;
705 if (v4src != null) {
706 try {
707 Field field = InputSource.class.getDeclaredField("modelId");
708 field.setAccessible(true);
709 field.set(v4src, ModelProblemUtils.toId(model));
710 } catch (Throwable t) {
711
712 throw new IllegalStateException("Unable to set modelId on InputSource", t);
713 }
714 }
715 } catch (XmlReaderException e) {
716 problems.add(
717 Severity.FATAL,
718 ModelProblem.Version.BASE,
719 "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage(),
720 e);
721 throw problems.newModelBuilderException();
722 } catch (IOException e) {
723 String msg = e.getMessage();
724 if (msg == null || msg.isEmpty()) {
725
726 if (e.getClass().getName().endsWith("MalformedInputException")) {
727 msg = "Some input bytes do not match the file encoding.";
728 } else {
729 msg = e.getClass().getSimpleName();
730 }
731 }
732 problems.add(
733 Severity.FATAL,
734 ModelProblem.Version.BASE,
735 "Non-readable POM " + modelSource.getLocation() + ": " + msg,
736 e);
737 throw problems.newModelBuilderException();
738 }
739
740 if (modelSource.getPath() != null) {
741 model = model.withPomFile(modelSource.getPath());
742
743
744 if (model.getSubprojects().isEmpty()
745 && model.getModules().isEmpty()
746
747 && !MODEL_VERSION_4_0_0.equals(model.getModelVersion())
748
749
750 && Type.POM.equals(model.getPackaging())) {
751 List<String> subprojects = new ArrayList<>();
752 try (Stream<Path> files = Files.list(model.getProjectDirectory())) {
753 for (Path f : files.toList()) {
754 if (Files.isDirectory(f)) {
755 Path subproject = modelProcessor.locateExistingPom(f);
756 if (subproject != null) {
757 subprojects.add(f.getFileName().toString());
758 }
759 }
760 }
761 if (!subprojects.isEmpty()) {
762 model = model.withSubprojects(subprojects);
763 }
764 } catch (IOException e) {
765 problems.add(Severity.FATAL, ModelProblem.Version.V41, "Error discovering subprojects", e);
766 }
767 }
768 }
769
770 problems.setSource(model);
771 modelValidator.validateFileModel(model, request, problems);
772 if (hasFatalErrors(problems)) {
773 throw problems.newModelBuilderException();
774 }
775
776 return model;
777 }
778
779 Model readRawModel(ModelBuilderRequest request, DefaultModelProblemCollector problems)
780 throws ModelBuilderException {
781 ModelSource modelSource = request.getSource();
782
783 ModelData modelData =
784 cache(getModelCache(request), modelSource, RAW, () -> doReadRawModel(modelSource, request, problems));
785
786 return modelData.model();
787 }
788
789 private ModelData doReadRawModel(
790 ModelSource modelSource, ModelBuilderRequest request, DefaultModelProblemCollector problems)
791 throws ModelBuilderException {
792 Model rawModel = readFileModel(request, problems);
793 if (Features.buildConsumer(request.getUserProperties()) && modelSource.getPath() != null) {
794 Path pomFile = modelSource.getPath();
795
796 try {
797 ModelTransformerContextBuilder transformerContextBuilder = getTransformerContextBuilder(request);
798 if (transformerContextBuilder != null) {
799 ModelTransformerContext context = transformerContextBuilder.initialize(request, problems);
800 rawModel = this.transformer.transform(context, rawModel, pomFile);
801 }
802 } catch (ModelTransformerException e) {
803 problems.add(Severity.FATAL, ModelProblem.Version.V40, null, e);
804 }
805 }
806
807 String namespace = rawModel.getNamespaceUri();
808 if (rawModel.getModelVersion() == null && namespace != null && namespace.startsWith(NAMESPACE_PREFIX)) {
809 rawModel = rawModel.withModelVersion(namespace.substring(NAMESPACE_PREFIX.length()));
810 }
811
812 modelValidator.validateRawModel(rawModel, request, problems);
813
814 if (hasFatalErrors(problems)) {
815 throw problems.newModelBuilderException();
816 }
817
818 return new ModelData(modelSource, rawModel);
819 }
820
821 static String getGroupId(Model model) {
822 String groupId = model.getGroupId();
823 if (groupId == null && model.getParent() != null) {
824 groupId = model.getParent().getGroupId();
825 }
826 return groupId;
827 }
828
829 private String getVersion(Model model) {
830 String version = model.getVersion();
831 if (version == null && model.getParent() != null) {
832 version = model.getParent().getVersion();
833 }
834 return version;
835 }
836
837 private DefaultProfileActivationContext getProfileActivationContext(ModelBuilderRequest request, Model model) {
838 DefaultProfileActivationContext context = new DefaultProfileActivationContext();
839
840 context.setActiveProfileIds(request.getActiveProfileIds());
841 context.setInactiveProfileIds(request.getInactiveProfileIds());
842 context.setSystemProperties(request.getSystemProperties());
843
844 Map<String, String> userProperties = new HashMap<>(request.getUserProperties());
845 if (!userProperties.containsKey(ProfileActivationContext.PROPERTY_NAME_PACKAGING)) {
846 userProperties.put(ProfileActivationContext.PROPERTY_NAME_PACKAGING, model.getPackaging());
847 }
848 context.setUserProperties(userProperties);
849 context.setProjectDirectory(model.getProjectDirectory());
850
851 return context;
852 }
853
854 private void checkPluginVersions(List<Model> lineage, ModelBuilderRequest request, ModelProblemCollector problems) {
855 if (request.getValidationLevel() < ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_2_0) {
856 return;
857 }
858
859 Map<String, Plugin> plugins = new HashMap<>();
860 Map<String, String> versions = new HashMap<>();
861 Map<String, String> managedVersions = new HashMap<>();
862
863 for (int i = lineage.size() - 1; i >= 0; i--) {
864 Model model = lineage.get(i);
865 Build build = model.getBuild();
866 if (build != null) {
867 for (Plugin plugin : build.getPlugins()) {
868 String key = plugin.getKey();
869 if (versions.get(key) == null) {
870 versions.put(key, plugin.getVersion());
871 plugins.put(key, plugin);
872 }
873 }
874 PluginManagement mgmt = build.getPluginManagement();
875 if (mgmt != null) {
876 for (Plugin plugin : mgmt.getPlugins()) {
877 String key = plugin.getKey();
878 managedVersions.computeIfAbsent(key, k -> plugin.getVersion());
879 }
880 }
881 }
882 }
883
884 for (String key : versions.keySet()) {
885 if (versions.get(key) == null && managedVersions.get(key) == null) {
886 InputLocation location = plugins.get(key).getLocation("");
887 problems.add(
888 Severity.WARNING,
889 ModelProblem.Version.V20,
890 "'build.plugins.plugin.version' for " + key + " is missing.",
891 location);
892 }
893 }
894 }
895
896 private Model assembleInheritance(
897 List<Model> lineage, ModelBuilderRequest request, ModelProblemCollector problems) {
898 Model parent = lineage.get(lineage.size() - 1);
899 for (int i = lineage.size() - 2; i >= 0; i--) {
900 Model child = lineage.get(i);
901 parent = inheritanceAssembler.assembleModelInheritance(child, parent, request, problems);
902 }
903 return parent;
904 }
905
906 private Map<String, Activation> getProfileActivations(Model model) {
907 return model.getProfiles().stream()
908 .filter(p -> p.getActivation() != null)
909 .collect(Collectors.toMap(Profile::getId, Profile::getActivation));
910 }
911
912 private Model injectProfileActivations(Model model, Map<String, Activation> activations) {
913 List<Profile> profiles = new ArrayList<>();
914 boolean modified = false;
915 for (Profile profile : model.getProfiles()) {
916 Activation activation = profile.getActivation();
917 if (activation != null) {
918
919 profile = profile.withActivation(activations.get(profile.getId()));
920 modified = true;
921 }
922 profiles.add(profile);
923 }
924 return modified ? model.withProfiles(profiles) : model;
925 }
926
927 private Model interpolateModel(Model model, ModelBuilderRequest request, ModelProblemCollector problems) {
928 Model interpolatedModel =
929 modelInterpolator.interpolateModel(model, model.getProjectDirectory(), request, problems);
930 if (interpolatedModel.getParent() != null) {
931 StringSearchInterpolator ssi = new StringSearchInterpolator();
932 ssi.addValueSource(new MapBasedValueSource(request.getSession().getUserProperties()));
933 ssi.addValueSource(new MapBasedValueSource(model.getProperties()));
934 ssi.addValueSource(new MapBasedValueSource(request.getSession().getSystemProperties()));
935 try {
936 String interpolated =
937 ssi.interpolate(interpolatedModel.getParent().getVersion());
938 interpolatedModel = interpolatedModel.withParent(
939 interpolatedModel.getParent().withVersion(interpolated));
940 } catch (Exception e) {
941 problems.add(
942 Severity.ERROR,
943 ModelProblem.Version.BASE,
944 "Failed to interpolate field: "
945 + interpolatedModel.getParent().getVersion()
946 + " on class: ",
947 e);
948 }
949 }
950 interpolatedModel = interpolatedModel.withPomFile(model.getPomFile());
951 return interpolatedModel;
952 }
953
954 private ModelData readParent(
955 Model childModel,
956 ModelSource childSource,
957 ModelBuilderRequest request,
958 DefaultModelProblemCollector problems)
959 throws ModelBuilderException {
960 ModelData parentData = null;
961
962 Parent parent = childModel.getParent();
963 if (parent != null) {
964 parentData = readParentLocally(childModel, childSource, request, problems);
965 if (parentData == null) {
966 parentData = readParentExternally(childModel, request, problems);
967 }
968
969 Model parentModel = parentData.model();
970 if (!"pom".equals(parentModel.getPackaging())) {
971 problems.add(
972 Severity.ERROR,
973 ModelProblem.Version.BASE,
974 "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint(parentModel)
975 + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"",
976 parentModel.getLocation("packaging"));
977 }
978 }
979
980 return parentData;
981 }
982
983 private ModelData readParentLocally(
984 Model childModel,
985 ModelSource childSource,
986 ModelBuilderRequest request,
987 DefaultModelProblemCollector problems)
988 throws ModelBuilderException {
989 final Parent parent = childModel.getParent();
990 final ModelSource candidateSource;
991 final Model candidateModel;
992 final WorkspaceModelResolver resolver = getWorkspaceModelResolver(request);
993 if (resolver == null) {
994 candidateSource = getParentPomFile(childModel, childSource);
995
996 if (candidateSource == null) {
997 return null;
998 }
999
1000 ModelBuilderRequest candidateBuildRequest = ModelBuilderRequest.build(request, candidateSource);
1001
1002 candidateModel = readRawModel(candidateBuildRequest, problems);
1003 } else {
1004 try {
1005 candidateModel =
1006 resolver.resolveRawModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
1007 } catch (ModelBuilderException e) {
1008 problems.add(Severity.FATAL, ModelProblem.Version.BASE, e.getMessage(), parent.getLocation(""), e);
1009 throw problems.newModelBuilderException();
1010 }
1011 if (candidateModel == null) {
1012 return null;
1013 }
1014 candidateSource = ModelSource.fromPath(candidateModel.getPomFile());
1015 }
1016
1017
1018
1019
1020
1021
1022
1023 String groupId = getGroupId(candidateModel);
1024 String artifactId = candidateModel.getArtifactId();
1025
1026 if (groupId == null
1027 || !groupId.equals(parent.getGroupId())
1028 || artifactId == null
1029 || !artifactId.equals(parent.getArtifactId())) {
1030 StringBuilder buffer = new StringBuilder(256);
1031 buffer.append("'parent.relativePath'");
1032 if (childModel != problems.getRootModel()) {
1033 buffer.append(" of POM ").append(ModelProblemUtils.toSourceHint(childModel));
1034 }
1035 buffer.append(" points at ").append(groupId).append(':').append(artifactId);
1036 buffer.append(" instead of ").append(parent.getGroupId()).append(':');
1037 buffer.append(parent.getArtifactId()).append(", please verify your project structure");
1038
1039 problems.setSource(childModel);
1040 problems.add(Severity.WARNING, ModelProblem.Version.BASE, buffer.toString(), parent.getLocation(""));
1041 return null;
1042 }
1043
1044 String version = getVersion(candidateModel);
1045 if (version != null && parent.getVersion() != null && !version.equals(parent.getVersion())) {
1046 try {
1047 VersionRange parentRange = versionParser.parseVersionRange(parent.getVersion());
1048 if (!parentRange.contains(versionParser.parseVersion(version))) {
1049
1050 return null;
1051 }
1052
1053
1054 String rawChildModelVersion = childModel.getVersion();
1055
1056 if (rawChildModelVersion == null) {
1057
1058 problems.add(
1059 Severity.FATAL,
1060 ModelProblem.Version.V31,
1061 "Version must be a constant",
1062 childModel.getLocation(""));
1063
1064 } else {
1065 if (rawChildVersionReferencesParent(rawChildModelVersion)) {
1066
1067 problems.add(
1068 Severity.FATAL,
1069 ModelProblem.Version.V31,
1070 "Version must be a constant",
1071 childModel.getLocation("version"));
1072 }
1073 }
1074
1075
1076 } catch (VersionParserException e) {
1077
1078 return null;
1079 }
1080 }
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091 return new ModelData(candidateSource, candidateModel);
1092 }
1093
1094 private boolean rawChildVersionReferencesParent(String rawChildModelVersion) {
1095 return rawChildModelVersion.equals("${pom.version}")
1096 || rawChildModelVersion.equals("${project.version}")
1097 || rawChildModelVersion.equals("${pom.parent.version}")
1098 || rawChildModelVersion.equals("${project.parent.version}");
1099 }
1100
1101 private ModelSource getParentPomFile(Model childModel, ModelSource source) {
1102 String parentPath = childModel.getParent().getRelativePath();
1103 if (parentPath == null || parentPath.isEmpty()) {
1104 return null;
1105 } else {
1106 return source.resolve(modelProcessor::locateExistingPom, parentPath);
1107 }
1108 }
1109
1110 private ModelData readParentExternally(
1111 Model childModel, ModelBuilderRequest request, DefaultModelProblemCollector problems)
1112 throws ModelBuilderException {
1113 problems.setSource(childModel);
1114
1115 Parent parent = childModel.getParent();
1116
1117 String groupId = parent.getGroupId();
1118 String artifactId = parent.getArtifactId();
1119 String version = parent.getVersion();
1120
1121 ModelResolver modelResolver = getModelResolver(request);
1122 Objects.requireNonNull(
1123 modelResolver,
1124 String.format(
1125 "request.modelResolver cannot be null (parent POM %s and POM %s)",
1126 ModelProblemUtils.toId(groupId, artifactId, version),
1127 ModelProblemUtils.toSourceHint(childModel)));
1128
1129 ModelSource modelSource;
1130 try {
1131 AtomicReference<Parent> modified = new AtomicReference<>();
1132 Session session = request.getSession()
1133 .withRemoteRepositories(request.getModelRepositoryHolder().getRepositories());
1134 modelSource = modelResolver.resolveModel(session, parent, modified);
1135 if (modified.get() != null) {
1136 parent = modified.get();
1137 }
1138 } catch (ModelResolverException e) {
1139
1140 StringBuilder buffer = new StringBuilder(256);
1141 buffer.append("Non-resolvable parent POM");
1142 if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
1143 buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
1144 }
1145 if (childModel != problems.getRootModel()) {
1146 buffer.append(" for ").append(ModelProblemUtils.toId(childModel));
1147 }
1148 buffer.append(": ").append(e.getMessage());
1149 if (childModel.getProjectDirectory() != null) {
1150 if (parent.getRelativePath() == null || parent.getRelativePath().isEmpty()) {
1151 buffer.append(" and 'parent.relativePath' points at no local POM");
1152 } else {
1153 buffer.append(" and 'parent.relativePath' points at wrong local POM");
1154 }
1155 }
1156
1157 problems.add(Severity.FATAL, ModelProblem.Version.BASE, buffer.toString(), parent.getLocation(""), e);
1158 throw problems.newModelBuilderException();
1159 }
1160
1161 int validationLevel = Math.min(request.getValidationLevel(), ModelBuilderRequest.VALIDATION_LEVEL_MAVEN_2_0);
1162 ModelBuilderRequest lenientRequest = ModelBuilderRequest.builder(request)
1163 .validationLevel(validationLevel)
1164 .projectBuild(false)
1165 .source(modelSource)
1166 .build();
1167
1168 Model parentModel = readRawModel(lenientRequest, problems);
1169
1170 if (!parent.getVersion().equals(version)) {
1171 String rawChildModelVersion = childModel.getVersion();
1172
1173 if (rawChildModelVersion == null) {
1174
1175 problems.add(
1176 Severity.FATAL,
1177 ModelProblem.Version.V31,
1178 "Version must be a constant",
1179 childModel.getLocation(""));
1180
1181 } else {
1182 if (rawChildVersionReferencesParent(rawChildModelVersion)) {
1183
1184 problems.add(
1185 Severity.FATAL,
1186 ModelProblem.Version.V31,
1187 "Version must be a constant",
1188 childModel.getLocation("version"));
1189 }
1190 }
1191
1192
1193 }
1194
1195 return new ModelData(modelSource, parentModel);
1196 }
1197
1198 private Model getSuperModel(String modelVersion) {
1199 return superPomProvider.getSuperPom(modelVersion);
1200 }
1201
1202 private Model importDependencyManagement(
1203 Model model,
1204 ModelBuilderRequest request,
1205 DefaultModelProblemCollector problems,
1206 Collection<String> importIds) {
1207 DependencyManagement depMgmt = model.getDependencyManagement();
1208
1209 if (depMgmt == null) {
1210 return model;
1211 }
1212
1213 String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion();
1214
1215 importIds.add(importing);
1216
1217 List<DependencyManagement> importMgmts = null;
1218
1219 List<Dependency> deps = new ArrayList<>(depMgmt.getDependencies());
1220 for (Iterator<Dependency> it = deps.iterator(); it.hasNext(); ) {
1221 Dependency dependency = it.next();
1222
1223 if (!("pom".equals(dependency.getType()) && "import".equals(dependency.getScope()))
1224 || "bom".equals(dependency.getType())) {
1225 continue;
1226 }
1227
1228 it.remove();
1229
1230 DependencyManagement importMgmt = loadDependencyManagement(model, request, problems, dependency, importIds);
1231
1232 if (importMgmt != null) {
1233 if (importMgmts == null) {
1234 importMgmts = new ArrayList<>();
1235 }
1236
1237 importMgmts.add(importMgmt);
1238 }
1239 }
1240
1241 importIds.remove(importing);
1242
1243 model = model.withDependencyManagement(model.getDependencyManagement().withDependencies(deps));
1244
1245 return dependencyManagementImporter.importManagement(model, importMgmts, request, problems);
1246 }
1247
1248 private DependencyManagement loadDependencyManagement(
1249 Model model,
1250 ModelBuilderRequest request,
1251 DefaultModelProblemCollector problems,
1252 Dependency dependency,
1253 Collection<String> importIds) {
1254 String groupId = dependency.getGroupId();
1255 String artifactId = dependency.getArtifactId();
1256 String version = dependency.getVersion();
1257
1258 if (groupId == null || groupId.isEmpty()) {
1259 problems.add(
1260 Severity.ERROR,
1261 ModelProblem.Version.BASE,
1262 "'dependencyManagement.dependencies.dependency.groupId' for " + dependency.getManagementKey()
1263 + " is missing.",
1264 dependency.getLocation(""));
1265 return null;
1266 }
1267 if (artifactId == null || artifactId.isEmpty()) {
1268 problems.add(
1269 Severity.ERROR,
1270 ModelProblem.Version.BASE,
1271 "'dependencyManagement.dependencies.dependency.artifactId' for " + dependency.getManagementKey()
1272 + " is missing.",
1273 dependency.getLocation(""));
1274 return null;
1275 }
1276 if (version == null || version.isEmpty()) {
1277 problems.add(
1278 Severity.ERROR,
1279 ModelProblem.Version.BASE,
1280 "'dependencyManagement.dependencies.dependency.version' for " + dependency.getManagementKey()
1281 + " is missing.",
1282 dependency.getLocation(""));
1283 return null;
1284 }
1285
1286 String imported = groupId + ':' + artifactId + ':' + version;
1287
1288 if (importIds.contains(imported)) {
1289 StringBuilder message =
1290 new StringBuilder("The dependencies of type=pom and with scope=import form a cycle: ");
1291 for (String modelId : importIds) {
1292 message.append(modelId).append(" -> ");
1293 }
1294 message.append(imported);
1295 problems.add(Severity.ERROR, ModelProblem.Version.BASE, message.toString());
1296
1297 return null;
1298 }
1299
1300 Model importModel = cache(
1301 getModelCache(request),
1302 groupId,
1303 artifactId,
1304 version,
1305 IMPORT,
1306 () -> doLoadDependencyManagement(
1307 model, request, problems, dependency, groupId, artifactId, version, importIds));
1308 DependencyManagement importMgmt = importModel != null ? importModel.getDependencyManagement() : null;
1309 if (importMgmt == null) {
1310 importMgmt = DependencyManagement.newInstance();
1311 }
1312
1313
1314 List<Exclusion> exclusions = dependency.getExclusions();
1315 if (importMgmt != null && !exclusions.isEmpty()) {
1316
1317 List<Dependency> dependencies = importMgmt.getDependencies().stream()
1318 .filter(candidate -> exclusions.stream().noneMatch(exclusion -> match(exclusion, candidate)))
1319 .map(candidate -> addExclusions(candidate, exclusions))
1320 .collect(Collectors.toList());
1321 importMgmt = importMgmt.withDependencies(dependencies);
1322 }
1323
1324 return importMgmt;
1325 }
1326
1327 private static org.apache.maven.api.model.Dependency addExclusions(
1328 org.apache.maven.api.model.Dependency candidate, List<Exclusion> exclusions) {
1329 return candidate.withExclusions(Stream.concat(candidate.getExclusions().stream(), exclusions.stream())
1330 .toList());
1331 }
1332
1333 private boolean match(Exclusion exclusion, Dependency candidate) {
1334 return match(exclusion.getGroupId(), candidate.getGroupId())
1335 && match(exclusion.getArtifactId(), candidate.getArtifactId());
1336 }
1337
1338 private boolean match(String match, String text) {
1339 return match.equals("*") || match.equals(text);
1340 }
1341
1342 @SuppressWarnings("checkstyle:parameternumber")
1343 private Model doLoadDependencyManagement(
1344 Model model,
1345 ModelBuilderRequest request,
1346 DefaultModelProblemCollector problems,
1347 Dependency dependency,
1348 String groupId,
1349 String artifactId,
1350 String version,
1351 Collection<String> importIds) {
1352 final WorkspaceModelResolver workspaceResolver = getWorkspaceModelResolver(request);
1353 final ModelResolver modelResolver = getModelResolver(request);
1354 if (workspaceResolver == null && modelResolver == null) {
1355 throw new NullPointerException(String.format(
1356 "request.workspaceModelResolver and request.modelResolver cannot be null (parent POM %s and POM %s)",
1357 ModelProblemUtils.toId(groupId, artifactId, version), ModelProblemUtils.toSourceHint(model)));
1358 }
1359
1360 Model importModel = null;
1361 if (workspaceResolver != null) {
1362 try {
1363 importModel = workspaceResolver.resolveEffectiveModel(groupId, artifactId, version);
1364 } catch (ModelBuilderException e) {
1365 problems.add(Severity.FATAL, ModelProblem.Version.BASE, null, e);
1366 return null;
1367 }
1368 }
1369
1370
1371 if (importModel == null) {
1372 final ModelSource importSource;
1373 try {
1374 Session session = request.getSession()
1375 .withRemoteRepositories(
1376 request.getModelRepositoryHolder().getRepositories());
1377 importSource = modelResolver.resolveModel(session, dependency, new AtomicReference<>());
1378 } catch (ModelBuilderException e) {
1379 StringBuilder buffer = new StringBuilder(256);
1380 buffer.append("Non-resolvable import POM");
1381 if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
1382 buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
1383 }
1384 buffer.append(": ").append(e.getMessage());
1385
1386 problems.add(
1387 Severity.ERROR, ModelProblem.Version.BASE, buffer.toString(), dependency.getLocation(""), e);
1388 return null;
1389 }
1390
1391 Path rootDirectory;
1392 try {
1393 rootDirectory = request.getSession().getRootDirectory();
1394 } catch (IllegalStateException e) {
1395 rootDirectory = null;
1396 }
1397 if (importSource.getPath() != null && rootDirectory != null) {
1398 Path sourcePath = importSource.getPath();
1399 if (sourcePath.startsWith(rootDirectory)) {
1400 problems.add(
1401 Severity.WARNING,
1402 ModelProblem.Version.BASE,
1403 "BOM imports from within reactor should be avoided",
1404 dependency.getLocation(""));
1405 }
1406 }
1407
1408 final ModelBuilderResult importResult;
1409 try {
1410 ModelBuilderRequest importRequest = ModelBuilderRequest.builder()
1411 .session(request.getSession()
1412 .withRemoteRepositories(
1413 request.getModelRepositoryHolder().getRepositories()))
1414 .validationLevel(ModelBuilderRequest.VALIDATION_LEVEL_MINIMAL)
1415 .systemProperties(request.getSystemProperties())
1416 .userProperties(request.getUserProperties())
1417 .source(importSource)
1418 .modelResolver(modelResolver)
1419 .modelCache(request.getModelCache())
1420 .modelRepositoryHolder(
1421 request.getModelRepositoryHolder().copy())
1422 .twoPhaseBuilding(false)
1423 .build();
1424 importResult = build(importRequest, importIds);
1425 } catch (ModelBuilderException e) {
1426 e.getResult().getProblems().forEach(problems::add);
1427 return null;
1428 }
1429
1430 importResult.getProblems().forEach(problems::add);
1431
1432 importModel = importResult.getEffectiveModel();
1433 }
1434
1435 return importModel;
1436 }
1437
1438 private static <T> T cache(
1439 ModelCache cache, String groupId, String artifactId, String version, String tag, Callable<T> supplier) {
1440 Supplier<T> s = asSupplier(supplier);
1441 if (cache == null) {
1442 return s.get();
1443 } else {
1444 return cache.computeIfAbsent(groupId, artifactId, version, tag, s);
1445 }
1446 }
1447
1448 private static <T> T cache(ModelCache cache, Source source, String tag, Callable<T> supplier) {
1449 Supplier<T> s = asSupplier(supplier);
1450 if (cache == null) {
1451 return s.get();
1452 } else {
1453 return cache.computeIfAbsent(source, tag, s);
1454 }
1455 }
1456
1457 private static <T> Supplier<T> asSupplier(Callable<T> supplier) {
1458 return () -> {
1459 try {
1460 return supplier.call();
1461 } catch (Exception e) {
1462 uncheckedThrow(e);
1463 return null;
1464 }
1465 };
1466 }
1467
1468 static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
1469 throw (T) t;
1470 }
1471
1472 private Model fireEvent(
1473 Model model,
1474 ModelBuilderRequest request,
1475 ModelProblemCollector problems,
1476 BiConsumer<ModelBuildingListener, ModelBuildingEvent> catapult) {
1477 ModelBuildingListener listener = getModelBuildingListener(request);
1478
1479 if (listener != null) {
1480 AtomicReference<Model> m = new AtomicReference<>(model);
1481
1482 ModelBuildingEvent event = new DefaultModelBuildingEvent(model, m::set, request, problems);
1483
1484 catapult.accept(listener, event);
1485
1486 return m.get();
1487 }
1488
1489 return model;
1490 }
1491
1492 private boolean containsCoordinates(String message, String groupId, String artifactId, String version) {
1493 return message != null
1494 && (groupId == null || message.contains(groupId))
1495 && (artifactId == null || message.contains(artifactId))
1496 && (version == null || message.contains(version));
1497 }
1498
1499 protected boolean hasModelErrors(ModelProblemCollector problems) {
1500 return problems.hasErrors();
1501 }
1502
1503 protected boolean hasFatalErrors(ModelProblemCollector problems) {
1504 return problems.hasFatalErrors();
1505 }
1506
1507 ModelProcessor getModelProcessor() {
1508 return modelProcessor;
1509 }
1510
1511 private static ModelCache getModelCache(ModelBuilderRequest request) {
1512 return request.getModelCache();
1513 }
1514
1515 private static ModelBuildingListener getModelBuildingListener(ModelBuilderRequest request) {
1516 return (ModelBuildingListener) request.getListener();
1517 }
1518
1519 private static WorkspaceModelResolver getWorkspaceModelResolver(ModelBuilderRequest request) {
1520 return null;
1521 }
1522
1523 private static ModelResolver getModelResolver(ModelBuilderRequest request) {
1524 return request.getModelResolver();
1525 }
1526
1527 private static ModelTransformerContextBuilder getTransformerContextBuilder(ModelBuilderRequest request) {
1528 return request.getTransformerContextBuilder();
1529 }
1530 }