1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.model.building;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.File;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.LinkedHashSet;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Objects;
36 import java.util.Optional;
37 import java.util.Properties;
38 import java.util.function.Consumer;
39 import java.util.stream.IntStream;
40
41 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
42 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
43 import org.apache.maven.artifact.versioning.VersionRange;
44 import org.apache.maven.model.Activation;
45 import org.apache.maven.model.Build;
46 import org.apache.maven.model.Dependency;
47 import org.apache.maven.model.DependencyManagement;
48 import org.apache.maven.model.InputLocation;
49 import org.apache.maven.model.InputLocationTracker;
50 import org.apache.maven.model.InputSource;
51 import org.apache.maven.model.Model;
52 import org.apache.maven.model.Parent;
53 import org.apache.maven.model.Plugin;
54 import org.apache.maven.model.PluginManagement;
55 import org.apache.maven.model.Profile;
56 import org.apache.maven.model.Repository;
57 import org.apache.maven.model.building.ModelProblem.Severity;
58 import org.apache.maven.model.building.ModelProblem.Version;
59 import org.apache.maven.model.composition.DependencyManagementImporter;
60 import org.apache.maven.model.inheritance.InheritanceAssembler;
61 import org.apache.maven.model.interpolation.ModelInterpolator;
62 import org.apache.maven.model.io.ModelParseException;
63 import org.apache.maven.model.management.DependencyManagementInjector;
64 import org.apache.maven.model.management.PluginManagementInjector;
65 import org.apache.maven.model.normalization.ModelNormalizer;
66 import org.apache.maven.model.path.ModelPathTranslator;
67 import org.apache.maven.model.path.ModelUrlNormalizer;
68 import org.apache.maven.model.path.ProfileActivationFilePathInterpolator;
69 import org.apache.maven.model.plugin.LifecycleBindingsInjector;
70 import org.apache.maven.model.plugin.PluginConfigurationExpander;
71 import org.apache.maven.model.plugin.ReportConfigurationExpander;
72 import org.apache.maven.model.plugin.ReportingConverter;
73 import org.apache.maven.model.profile.DefaultProfileActivationContext;
74 import org.apache.maven.model.profile.ProfileActivationContext;
75 import org.apache.maven.model.profile.ProfileInjector;
76 import org.apache.maven.model.profile.ProfileSelector;
77 import org.apache.maven.model.resolution.InvalidRepositoryException;
78 import org.apache.maven.model.resolution.ModelResolver;
79 import org.apache.maven.model.resolution.UnresolvableModelException;
80 import org.apache.maven.model.resolution.WorkspaceModelResolver;
81 import org.apache.maven.model.superpom.SuperPomProvider;
82 import org.apache.maven.model.validation.ModelValidator;
83 import org.codehaus.plexus.interpolation.InterpolationException;
84 import org.codehaus.plexus.interpolation.MapBasedValueSource;
85 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
86 import org.codehaus.plexus.interpolation.StringSearchInterpolator;
87 import org.codehaus.plexus.util.StringUtils;
88 import org.eclipse.sisu.Nullable;
89
90 import static org.apache.maven.model.building.Result.error;
91 import static org.apache.maven.model.building.Result.newResult;
92
93
94
95
96 @SuppressWarnings("UnusedReturnValue")
97 @Named
98 @Singleton
99 @Deprecated(since = "4.0.0")
100 public class DefaultModelBuilder implements ModelBuilder {
101 @Inject
102 private ModelProcessor modelProcessor;
103
104 @Inject
105 private ModelValidator modelValidator;
106
107 @Inject
108 private ModelNormalizer modelNormalizer;
109
110 @Inject
111 private ModelInterpolator modelInterpolator;
112
113 @Inject
114 private ModelPathTranslator modelPathTranslator;
115
116 @Inject
117 private ModelUrlNormalizer modelUrlNormalizer;
118
119 @Inject
120 private SuperPomProvider superPomProvider;
121
122 @Inject
123 private InheritanceAssembler inheritanceAssembler;
124
125 @Inject
126 private ProfileSelector profileSelector;
127
128 @Inject
129 private ProfileInjector profileInjector;
130
131 @Inject
132 private PluginManagementInjector pluginManagementInjector;
133
134 @Inject
135 private DependencyManagementInjector dependencyManagementInjector;
136
137 @Inject
138 private DependencyManagementImporter dependencyManagementImporter;
139
140 @Inject
141 @Nullable
142 private LifecycleBindingsInjector lifecycleBindingsInjector;
143
144 @Inject
145 private PluginConfigurationExpander pluginConfigurationExpander;
146
147 @Inject
148 private ReportConfigurationExpander reportConfigurationExpander;
149
150 @Inject
151 private ReportingConverter reportingConverter;
152
153 @Inject
154 private ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator;
155
156 public DefaultModelBuilder setModelProcessor(ModelProcessor modelProcessor) {
157 this.modelProcessor = modelProcessor;
158 return this;
159 }
160
161 public DefaultModelBuilder setModelValidator(ModelValidator modelValidator) {
162 this.modelValidator = modelValidator;
163 return this;
164 }
165
166 public DefaultModelBuilder setModelNormalizer(ModelNormalizer modelNormalizer) {
167 this.modelNormalizer = modelNormalizer;
168 return this;
169 }
170
171 public DefaultModelBuilder setModelInterpolator(ModelInterpolator modelInterpolator) {
172 this.modelInterpolator = modelInterpolator;
173 return this;
174 }
175
176 public DefaultModelBuilder setModelPathTranslator(ModelPathTranslator modelPathTranslator) {
177 this.modelPathTranslator = modelPathTranslator;
178 return this;
179 }
180
181 public DefaultModelBuilder setModelUrlNormalizer(ModelUrlNormalizer modelUrlNormalizer) {
182 this.modelUrlNormalizer = modelUrlNormalizer;
183 return this;
184 }
185
186 public DefaultModelBuilder setSuperPomProvider(SuperPomProvider superPomProvider) {
187 this.superPomProvider = superPomProvider;
188 return this;
189 }
190
191 public DefaultModelBuilder setProfileSelector(ProfileSelector profileSelector) {
192 this.profileSelector = profileSelector;
193 return this;
194 }
195
196 public DefaultModelBuilder setProfileInjector(ProfileInjector profileInjector) {
197 this.profileInjector = profileInjector;
198 return this;
199 }
200
201 public DefaultModelBuilder setInheritanceAssembler(InheritanceAssembler inheritanceAssembler) {
202 this.inheritanceAssembler = inheritanceAssembler;
203 return this;
204 }
205
206 public DefaultModelBuilder setDependencyManagementImporter(DependencyManagementImporter depMgmtImporter) {
207 this.dependencyManagementImporter = depMgmtImporter;
208 return this;
209 }
210
211 public DefaultModelBuilder setDependencyManagementInjector(DependencyManagementInjector depMgmtInjector) {
212 this.dependencyManagementInjector = depMgmtInjector;
213 return this;
214 }
215
216 public DefaultModelBuilder setLifecycleBindingsInjector(LifecycleBindingsInjector lifecycleBindingsInjector) {
217 this.lifecycleBindingsInjector = lifecycleBindingsInjector;
218 return this;
219 }
220
221 public DefaultModelBuilder setPluginConfigurationExpander(PluginConfigurationExpander pluginConfigurationExpander) {
222 this.pluginConfigurationExpander = pluginConfigurationExpander;
223 return this;
224 }
225
226 public DefaultModelBuilder setPluginManagementInjector(PluginManagementInjector pluginManagementInjector) {
227 this.pluginManagementInjector = pluginManagementInjector;
228 return this;
229 }
230
231 public DefaultModelBuilder setReportConfigurationExpander(ReportConfigurationExpander reportConfigurationExpander) {
232 this.reportConfigurationExpander = reportConfigurationExpander;
233 return this;
234 }
235
236 public DefaultModelBuilder setReportingConverter(ReportingConverter reportingConverter) {
237 this.reportingConverter = reportingConverter;
238 return this;
239 }
240
241 public DefaultModelBuilder setProfileActivationFilePathInterpolator(
242 ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator) {
243 this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator;
244 return this;
245 }
246
247 @SuppressWarnings("checkstyle:methodlength")
248 @Override
249 public ModelBuildingResult build(ModelBuildingRequest request) throws ModelBuildingException {
250 return build(request, new LinkedHashSet<String>());
251 }
252
253 @SuppressWarnings("checkstyle:methodlength")
254 protected ModelBuildingResult build(ModelBuildingRequest request, Collection<String> importIds)
255 throws ModelBuildingException {
256
257 DefaultModelBuildingResult result = new DefaultModelBuildingResult();
258
259 DefaultModelProblemCollector problems = new DefaultModelProblemCollector(result);
260
261
262 Model inputModel = request.getRawModel();
263 if (inputModel == null) {
264 inputModel = readModel(request.getModelSource(), request.getPomFile(), request, problems);
265 }
266
267
268 DefaultProfileActivationContext profileActivationContext = getProfileActivationContext(request, inputModel);
269
270 problems.setSource("(external profiles)");
271 List<Profile> activeExternalProfiles =
272 profileSelector.getActiveProfiles(request.getProfiles(), profileActivationContext, problems);
273
274 result.setActiveExternalProfiles(activeExternalProfiles);
275
276 if (!activeExternalProfiles.isEmpty()) {
277 Properties profileProps = new Properties();
278 for (Profile profile : activeExternalProfiles) {
279 profileProps.putAll(profile.getProperties());
280 }
281 profileProps.putAll(profileActivationContext.getUserProperties());
282 profileActivationContext.setUserProperties(profileProps);
283 }
284
285 problems.setRootModel(inputModel);
286
287 ModelData resultData = new ModelData(request.getModelSource(), inputModel);
288 ModelData superData = new ModelData(null, getSuperModel());
289
290 Collection<String> parentIds = new LinkedHashSet<>();
291 List<ModelData> lineage = new ArrayList<>();
292
293 for (ModelData currentData = resultData; currentData != null; ) {
294 lineage.add(currentData);
295
296 Model rawModel = currentData.getModel();
297 currentData.setRawModel(rawModel);
298
299 Model tmpModel = rawModel.clone();
300 currentData.setModel(tmpModel);
301
302 problems.setSource(tmpModel);
303
304
305 modelNormalizer.mergeDuplicates(tmpModel, request, problems);
306
307 profileActivationContext.setProjectProperties(tmpModel.getProperties());
308
309 List<Profile> interpolatedProfiles = getInterpolatedProfiles(rawModel, profileActivationContext, problems);
310 tmpModel.setProfiles(interpolatedProfiles);
311
312 List<Profile> activePomProfiles =
313 profileSelector.getActiveProfiles(tmpModel.getProfiles(), profileActivationContext, problems);
314
315 List<Profile> rawProfiles = new ArrayList<>();
316 for (Profile activePomProfile : activePomProfiles) {
317 rawProfiles.add(rawModel.getProfiles().get(interpolatedProfiles.indexOf(activePomProfile)));
318 }
319 currentData.setActiveProfiles(rawProfiles);
320
321
322 for (Profile activeProfile : activePomProfiles) {
323 profileInjector.injectProfile(tmpModel, activeProfile, request, problems);
324 }
325
326 if (currentData == resultData) {
327 for (Profile activeProfile : activeExternalProfiles) {
328 profileInjector.injectProfile(tmpModel, activeProfile, request, problems);
329 }
330 }
331
332 if (currentData == superData) {
333 break;
334 }
335
336 configureResolver(request.getModelResolver(), tmpModel, problems);
337
338 ModelData parentData = readParent(tmpModel, currentData.getSource(), request, problems);
339
340 if (parentData == null) {
341 currentData = superData;
342 } else if (currentData == resultData) {
343 currentData.setGroupId(
344 currentData.getRawModel().getGroupId() == null
345 ? parentData.getGroupId()
346 : currentData.getRawModel().getGroupId());
347
348 currentData.setVersion(
349 currentData.getRawModel().getVersion() == null
350 ? parentData.getVersion()
351 : currentData.getRawModel().getVersion());
352
353 currentData.setArtifactId(currentData.getRawModel().getArtifactId());
354 parentIds.add(currentData.getId());
355
356 currentData.setGroupId(null);
357 currentData.setArtifactId(null);
358 currentData.setVersion(null);
359 currentData = parentData;
360 } else if (!parentIds.add(parentData.getId())) {
361 String message = "The parents form a cycle: ";
362 for (String modelId : parentIds) {
363 message += modelId + " -> ";
364 }
365 message += parentData.getId();
366
367 problems.add(new ModelProblemCollectorRequest(ModelProblem.Severity.FATAL, ModelProblem.Version.BASE)
368 .setMessage(message));
369
370 throw problems.newModelBuildingException();
371 } else {
372 currentData = parentData;
373 }
374 }
375
376 problems.setSource(inputModel);
377 checkPluginVersions(lineage, request, problems);
378
379
380 assembleInheritance(lineage, request, problems);
381
382 Model resultModel = resultData.getModel();
383
384 problems.setSource(resultModel);
385 problems.setRootModel(resultModel);
386
387
388 resultModel = interpolateModel(resultModel, request, problems);
389 resultData.setModel(resultModel);
390
391 if (resultModel.getParent() != null) {
392 final ModelData parentData = lineage.get(1);
393 if (parentData.getVersion() == null || parentData.getVersion().contains("${")) {
394 final Model interpolatedParent = interpolateModel(parentData.getModel(), request, problems);
395
396 parentData.setVersion(interpolatedParent.getVersion());
397 }
398 }
399
400
401 modelUrlNormalizer.normalize(resultModel, request);
402
403
404 configureResolver(request.getModelResolver(), resultModel, problems, true);
405
406 resultData.setGroupId(resultModel.getGroupId());
407 resultData.setArtifactId(resultModel.getArtifactId());
408 resultData.setVersion(resultModel.getVersion());
409
410 result.setEffectiveModel(resultModel);
411
412 for (ModelData currentData : lineage) {
413 String modelId = (currentData != superData) ? currentData.getId() : "";
414
415 result.addModelId(modelId);
416 result.setActivePomProfiles(modelId, currentData.getActiveProfiles());
417 result.setRawModel(modelId, currentData.getRawModel());
418 }
419
420 if (!request.isTwoPhaseBuilding()) {
421 build(request, result, importIds);
422 }
423
424 return result;
425 }
426
427 @FunctionalInterface
428 private interface InterpolateString {
429 String apply(String s) throws InterpolationException;
430 }
431
432 private List<Profile> getInterpolatedProfiles(
433 Model rawModel, DefaultProfileActivationContext context, DefaultModelProblemCollector problems) {
434 List<Profile> interpolatedActivations = getProfiles(rawModel, true);
435
436 if (interpolatedActivations.isEmpty()) {
437 return Collections.emptyList();
438 }
439 RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
440
441 interpolator.addValueSource(new MapBasedValueSource(context.getProjectProperties()));
442 interpolator.addValueSource(new MapBasedValueSource(context.getUserProperties()));
443 interpolator.addValueSource(new MapBasedValueSource(context.getSystemProperties()));
444
445 class Interpolation {
446 final InputLocationTracker target;
447
448 final InterpolateString impl;
449
450 Interpolation(InputLocationTracker target, InterpolateString impl) {
451 this.target = target;
452 this.impl = impl;
453 }
454
455 void performFor(String value, String locationKey, Consumer<String> mutator) {
456 if (StringUtils.isEmpty(value)) {
457 return;
458 }
459 try {
460 mutator.accept(impl.apply(value));
461 } catch (InterpolationException e) {
462 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
463 .setMessage("Failed to interpolate value " + value + ": " + e.getMessage())
464 .setLocation(target.getLocation(locationKey))
465 .setException(e));
466 }
467 }
468 }
469 for (Profile profile : interpolatedActivations) {
470 Activation activation = profile.getActivation();
471 Optional<Activation> a = Optional.ofNullable(activation);
472 a.map(Activation::getFile).ifPresent(fa -> {
473 Interpolation nt =
474 new Interpolation(fa, s -> profileActivationFilePathInterpolator.interpolate(s, context));
475 nt.performFor(fa.getExists(), "exists", fa::setExists);
476 nt.performFor(fa.getMissing(), "missing", fa::setMissing);
477 });
478 a.map(Activation::getOs).ifPresent(oa -> {
479 Interpolation nt = new Interpolation(oa, interpolator::interpolate);
480 nt.performFor(oa.getArch(), "arch", oa::setArch);
481 nt.performFor(oa.getFamily(), "family", oa::setFamily);
482 nt.performFor(oa.getName(), "name", oa::setName);
483 nt.performFor(oa.getVersion(), "version", oa::setVersion);
484 });
485 a.map(Activation::getProperty).ifPresent(pa -> {
486 Interpolation nt = new Interpolation(pa, interpolator::interpolate);
487 nt.performFor(pa.getName(), "name", pa::setName);
488 nt.performFor(pa.getValue(), "value", pa::setValue);
489 });
490 a.map(Activation::getJdk).ifPresent(ja -> new Interpolation(activation, interpolator::interpolate)
491 .performFor(ja, "jdk", activation::setJdk));
492 }
493 return interpolatedActivations;
494 }
495
496 @Override
497 public ModelBuildingResult build(ModelBuildingRequest request, ModelBuildingResult result)
498 throws ModelBuildingException {
499 return build(request, result, new LinkedHashSet<String>());
500 }
501
502 private ModelBuildingResult build(
503 ModelBuildingRequest request, ModelBuildingResult result, Collection<String> imports)
504 throws ModelBuildingException {
505
506 Model resultModel = result.getEffectiveModel();
507
508 DefaultModelProblemCollector problems = new DefaultModelProblemCollector(result);
509 problems.setSource(resultModel);
510 problems.setRootModel(resultModel);
511
512
513 modelPathTranslator.alignToBaseDirectory(resultModel, resultModel.getProjectDirectory(), request);
514
515
516 pluginManagementInjector.injectManagement(resultModel, request, problems);
517
518 fireEvent(resultModel, request, problems, ModelBuildingEventCatapult.BUILD_EXTENSIONS_ASSEMBLED);
519
520 if (request.isProcessPlugins()) {
521 if (lifecycleBindingsInjector == null) {
522 throw new IllegalStateException("lifecycle bindings injector is missing");
523 }
524
525
526 lifecycleBindingsInjector.injectLifecycleBindings(resultModel, request, problems);
527 }
528
529
530 importDependencyManagement(resultModel, request, problems, imports);
531
532
533 dependencyManagementInjector.injectManagement(resultModel, request, problems);
534
535 modelNormalizer.injectDefaultValues(resultModel, request, problems);
536
537 if (request.isProcessPlugins()) {
538
539 reportConfigurationExpander.expandPluginConfiguration(resultModel, request, problems);
540
541
542 reportingConverter.convertReporting(resultModel, request, problems);
543
544
545 pluginConfigurationExpander.expandPluginConfiguration(resultModel, request, problems);
546 }
547
548
549 modelValidator.validateEffectiveModel(resultModel, request, problems);
550
551 if (hasModelErrors(problems)) {
552 throw problems.newModelBuildingException();
553 }
554
555 return result;
556 }
557
558 @Override
559 public Result<? extends Model> buildRawModel(File pomFile, int validationLevel, boolean locationTracking) {
560 final ModelBuildingRequest request = new DefaultModelBuildingRequest()
561 .setValidationLevel(validationLevel)
562 .setLocationTracking(locationTracking);
563 final DefaultModelProblemCollector collector =
564 new DefaultModelProblemCollector(new DefaultModelBuildingResult());
565 try {
566 return newResult(readModel(null, pomFile, request, collector), collector.getProblems());
567 } catch (ModelBuildingException e) {
568 return error(collector.getProblems());
569 }
570 }
571
572 private Model readModel(
573 ModelSource modelSource, File pomFile, ModelBuildingRequest request, DefaultModelProblemCollector problems)
574 throws ModelBuildingException {
575 Model model;
576
577 if (modelSource == null) {
578 if (pomFile != null) {
579 modelSource = new FileModelSource(pomFile);
580 } else {
581 throw new NullPointerException("neither pomFile nor modelSource can be null");
582 }
583 }
584
585 problems.setSource(modelSource.getLocation());
586 try {
587 boolean strict = request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
588 InputSource source = request.isLocationTracking() ? new InputSource() : null;
589
590 Map<String, Object> options = new HashMap<>();
591 options.put(ModelProcessor.IS_STRICT, strict);
592 options.put(ModelProcessor.INPUT_SOURCE, source);
593 options.put(ModelProcessor.SOURCE, modelSource);
594
595 try {
596 model = modelProcessor.read(modelSource.getInputStream(), options);
597 } catch (ModelParseException e) {
598 if (!strict) {
599 throw e;
600 }
601
602 options.put(ModelProcessor.IS_STRICT, Boolean.FALSE);
603
604 try {
605 model = modelProcessor.read(modelSource.getInputStream(), options);
606 } catch (ModelParseException ne) {
607
608 throw e;
609 }
610
611 if (pomFile != null) {
612 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.V20)
613 .setMessage("Malformed POM " + modelSource.getLocation() + ": " + e.getMessage())
614 .setException(e));
615 } else {
616 problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.V20)
617 .setMessage("Malformed POM " + modelSource.getLocation() + ": " + e.getMessage())
618 .setException(e));
619 }
620 }
621
622 if (source != null) {
623 source.setModelId(ModelProblemUtils.toId(model));
624 source.setLocation(modelSource.getLocation());
625 }
626 } catch (ModelParseException e) {
627 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
628 .setMessage("Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage())
629 .setException(e));
630 throw problems.newModelBuildingException();
631 } catch (IOException e) {
632 String msg = e.getMessage();
633 if (msg == null || msg.length() <= 0) {
634
635 if (e.getClass().getName().endsWith("MalformedInputException")) {
636 msg = "Some input bytes do not match the file encoding.";
637 } else {
638 msg = e.getClass().getSimpleName();
639 }
640 }
641 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
642 .setMessage("Non-readable POM " + modelSource.getLocation() + ": " + msg)
643 .setException(e));
644 throw problems.newModelBuildingException();
645 }
646
647 model.setPomFile(pomFile);
648
649 problems.setSource(model);
650 modelValidator.validateRawModel(model, request, problems);
651
652 if (hasFatalErrors(problems)) {
653 throw problems.newModelBuildingException();
654 }
655
656 return model;
657 }
658
659 private DefaultProfileActivationContext getProfileActivationContext(ModelBuildingRequest request, Model rawModel) {
660 DefaultProfileActivationContext context = new DefaultProfileActivationContext();
661
662 context.setActiveProfileIds(request.getActiveProfileIds());
663 context.setInactiveProfileIds(request.getInactiveProfileIds());
664 context.setSystemProperties(request.getSystemProperties());
665
666 Properties userProperties = request.getUserProperties();
667 userProperties.computeIfAbsent(
668 (Object) ProfileActivationContext.PROPERTY_NAME_PACKAGING, (p) -> (Object) rawModel.getPackaging());
669 context.setUserProperties(userProperties);
670 context.setProjectDirectory(
671 (request.getPomFile() != null) ? request.getPomFile().getParentFile() : null);
672
673 return context;
674 }
675
676 private void configureResolver(ModelResolver modelResolver, Model model, DefaultModelProblemCollector problems) {
677 configureResolver(modelResolver, model, problems, false);
678 }
679
680 private void configureResolver(
681 ModelResolver modelResolver,
682 Model model,
683 DefaultModelProblemCollector problems,
684 boolean replaceRepositories) {
685 if (modelResolver == null) {
686 return;
687 }
688
689 problems.setSource(model);
690
691 List<Repository> repositories = model.getRepositories();
692
693 for (Repository repository : repositories) {
694 try {
695 modelResolver.addRepository(repository, replaceRepositories);
696 } catch (InvalidRepositoryException e) {
697 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
698 .setMessage("Invalid repository " + repository.getId() + ": " + e.getMessage())
699 .setLocation(repository.getLocation(""))
700 .setException(e));
701 }
702 }
703 }
704
705 private void checkPluginVersions(
706 List<ModelData> lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
707 if (request.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
708 return;
709 }
710
711 Map<String, Plugin> plugins = new HashMap<>();
712 Map<String, String> versions = new HashMap<>();
713 Map<String, String> managedVersions = new HashMap<>();
714
715 for (int i = lineage.size() - 1; i >= 0; i--) {
716 Model model = lineage.get(i).getModel();
717 Build build = model.getBuild();
718 if (build != null) {
719 for (Plugin plugin : build.getPlugins()) {
720 String key = plugin.getKey();
721 if (versions.get(key) == null) {
722 versions.put(key, plugin.getVersion());
723 plugins.put(key, plugin);
724 }
725 }
726 PluginManagement mgmt = build.getPluginManagement();
727 if (mgmt != null) {
728 for (Plugin plugin : mgmt.getPlugins()) {
729 String key = plugin.getKey();
730 if (managedVersions.get(key) == null) {
731 managedVersions.put(key, plugin.getVersion());
732 }
733 }
734 }
735 }
736 }
737
738 for (String key : versions.keySet()) {
739 if (versions.get(key) == null && managedVersions.get(key) == null) {
740 InputLocation location = plugins.get(key).getLocation("");
741 problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.V20)
742 .setMessage("'build.plugins.plugin.version' for " + key + " is missing.")
743 .setLocation(location));
744 }
745 }
746 }
747
748 private void assembleInheritance(
749 List<ModelData> lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
750 for (int i = lineage.size() - 2; i >= 0; i--) {
751 Model parent = lineage.get(i + 1).getModel();
752 Model child = lineage.get(i).getModel();
753 inheritanceAssembler.assembleModelInheritance(child, parent, request, problems);
754 }
755 }
756
757 private List<Profile> getProfiles(Model model, boolean clone) {
758 ArrayList<Profile> profiles = new ArrayList<>();
759 for (Profile profile : model.getProfiles()) {
760 if (clone) {
761 profile = profile.clone();
762 }
763 profiles.add(profile);
764 }
765 return profiles;
766 }
767
768 private Model interpolateModel(Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
769
770 List<Profile> originalProfiles = getProfiles(model, true);
771
772 Model interpolatedModel =
773 modelInterpolator.interpolateModel(model, model.getProjectDirectory(), request, problems);
774 if (interpolatedModel.getParent() != null) {
775 StringSearchInterpolator ssi = new StringSearchInterpolator();
776 ssi.addValueSource(new MapBasedValueSource(request.getUserProperties()));
777
778 ssi.addValueSource(new MapBasedValueSource(model.getProperties()));
779
780 ssi.addValueSource(new MapBasedValueSource(request.getSystemProperties()));
781
782 try {
783 String interpolated =
784 ssi.interpolate(interpolatedModel.getParent().getVersion());
785 interpolatedModel.getParent().setVersion(interpolated);
786 } catch (Exception e) {
787 ModelProblemCollectorRequest mpcr = new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
788 .setMessage("Failed to interpolate field: "
789 + interpolatedModel.getParent().getVersion()
790 + " on class: ")
791 .setException(e);
792 problems.add(mpcr);
793 }
794 }
795 interpolatedModel.setPomFile(model.getPomFile());
796
797
798 List<Profile> interpolatedProfiles = model.getProfiles();
799 IntStream.range(0, interpolatedProfiles.size()).forEach(i -> interpolatedProfiles
800 .get(i)
801 .setActivation(originalProfiles.get(i).getActivation()));
802
803 return interpolatedModel;
804 }
805
806 private ModelData readParent(
807 Model childModel,
808 ModelSource childSource,
809 ModelBuildingRequest request,
810 DefaultModelProblemCollector problems)
811 throws ModelBuildingException {
812 ModelData parentData;
813
814 Parent parent = childModel.getParent();
815
816 if (parent != null) {
817 String groupId = parent.getGroupId();
818 String artifactId = parent.getArtifactId();
819 String version = parent.getVersion();
820
821 parentData = getCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW);
822
823 if (parentData == null) {
824 parentData = readParentLocally(childModel, childSource, request, problems);
825
826 if (parentData == null) {
827 parentData = readParentExternally(childModel, request, problems);
828 }
829
830 putCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW, parentData);
831 } else {
832
833
834
835
836
837
838
839 File pomFile = parentData.getModel().getPomFile();
840 if (pomFile != null) {
841 FileModelSource pomSource = new FileModelSource(pomFile);
842 ModelSource expectedParentSource = getParentPomFile(childModel, childSource);
843
844 if (expectedParentSource == null
845 || (expectedParentSource instanceof ModelSource2
846 && !pomSource.equals(expectedParentSource))) {
847 parentData = readParentExternally(childModel, request, problems);
848 }
849 }
850 }
851
852 Model parentModel = parentData.getModel();
853
854 if (!"pom".equals(parentModel.getPackaging())) {
855 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
856 .setMessage("Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint(parentModel)
857 + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"")
858 .setLocation(parentModel.getLocation("packaging")));
859 }
860 } else {
861 parentData = null;
862 }
863
864 return parentData;
865 }
866
867 private ModelData readParentLocally(
868 Model childModel,
869 ModelSource childSource,
870 ModelBuildingRequest request,
871 DefaultModelProblemCollector problems)
872 throws ModelBuildingException {
873 final Parent parent = childModel.getParent();
874 final ModelSource candidateSource;
875 final Model candidateModel;
876 final WorkspaceModelResolver resolver = request.getWorkspaceModelResolver();
877 if (resolver == null) {
878 candidateSource = getParentPomFile(childModel, childSource);
879
880 if (candidateSource == null) {
881 return null;
882 }
883
884 File pomFile = null;
885 if (candidateSource instanceof FileModelSource source) {
886 pomFile = source.getPomFile();
887 }
888
889 candidateModel = readModel(candidateSource, pomFile, request, problems);
890 } else {
891 try {
892 candidateModel =
893 resolver.resolveRawModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
894 } catch (UnresolvableModelException e) {
895 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
896 .setMessage(e.getMessage().toString())
897 .setLocation(parent.getLocation(""))
898 .setException(e));
899 throw problems.newModelBuildingException();
900 }
901 if (candidateModel == null) {
902 return null;
903 }
904 candidateSource = new FileModelSource(candidateModel.getPomFile());
905 }
906
907
908
909
910
911
912
913 String groupId = candidateModel.getGroupId();
914 if (groupId == null && candidateModel.getParent() != null) {
915 groupId = candidateModel.getParent().getGroupId();
916 }
917 String artifactId = candidateModel.getArtifactId();
918 String version = candidateModel.getVersion();
919 if (version == null && candidateModel.getParent() != null) {
920 version = candidateModel.getParent().getVersion();
921 }
922
923 if (groupId == null
924 || !groupId.equals(parent.getGroupId())
925 || artifactId == null
926 || !artifactId.equals(parent.getArtifactId())) {
927 StringBuilder buffer = new StringBuilder(256);
928 buffer.append("'parent.relativePath'");
929 if (childModel != problems.getRootModel()) {
930 buffer.append(" of POM ").append(ModelProblemUtils.toSourceHint(childModel));
931 }
932 buffer.append(" points at ").append(groupId).append(':').append(artifactId);
933 buffer.append(" instead of ").append(parent.getGroupId()).append(':');
934 buffer.append(parent.getArtifactId()).append(", please verify your project structure");
935
936 problems.setSource(childModel);
937 problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.BASE)
938 .setMessage(buffer.toString())
939 .setLocation(parent.getLocation("")));
940 return null;
941 }
942 if (version != null && parent.getVersion() != null && !version.equals(parent.getVersion())) {
943 try {
944 VersionRange parentRange = VersionRange.createFromVersionSpec(parent.getVersion());
945 if (!parentRange.hasRestrictions()) {
946
947 return null;
948 }
949 if (!parentRange.containsVersion(new DefaultArtifactVersion(version))) {
950
951 return null;
952 }
953
954
955 String rawChildModelVersion = childModel.getVersion();
956
957 if (rawChildModelVersion == null) {
958
959 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
960 .setMessage("Version must be a constant")
961 .setLocation(childModel.getLocation("")));
962
963 } else {
964 if (rawChildVersionReferencesParent(rawChildModelVersion)) {
965
966 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
967 .setMessage("Version must be a constant")
968 .setLocation(childModel.getLocation("version")));
969 }
970 }
971
972
973 } catch (InvalidVersionSpecificationException e) {
974
975 return null;
976 }
977 }
978
979
980
981
982
983
984
985
986
987
988 ModelData parentData = new ModelData(candidateSource, candidateModel, groupId, artifactId, version);
989
990 return parentData;
991 }
992
993 private boolean rawChildVersionReferencesParent(String rawChildModelVersion) {
994 return rawChildModelVersion.equals("${pom.version}")
995 || rawChildModelVersion.equals("${project.version}")
996 || rawChildModelVersion.equals("${pom.parent.version}")
997 || rawChildModelVersion.equals("${project.parent.version}");
998 }
999
1000 private ModelSource getParentPomFile(Model childModel, ModelSource source) {
1001 if (!(source instanceof ModelSource2)) {
1002 return null;
1003 }
1004
1005 String parentPath = childModel.getParent().getRelativePath();
1006 if (parentPath == null) {
1007 parentPath = "../pom.xml";
1008 }
1009
1010 if (parentPath.length() <= 0) {
1011 return null;
1012 }
1013
1014 return ((ModelSource2) source).getRelatedSource(parentPath);
1015 }
1016
1017 private ModelData readParentExternally(
1018 Model childModel, ModelBuildingRequest request, DefaultModelProblemCollector problems)
1019 throws ModelBuildingException {
1020 problems.setSource(childModel);
1021
1022 Parent parent = childModel.getParent().clone();
1023
1024 String groupId = parent.getGroupId();
1025 String artifactId = parent.getArtifactId();
1026 String version = parent.getVersion();
1027
1028 ModelResolver modelResolver = request.getModelResolver();
1029 Objects.requireNonNull(
1030 modelResolver,
1031 String.format(
1032 "request.modelResolver cannot be null (parent POM %s and POM %s)",
1033 ModelProblemUtils.toId(groupId, artifactId, version),
1034 ModelProblemUtils.toSourceHint(childModel)));
1035
1036 ModelSource modelSource;
1037 try {
1038 modelSource = modelResolver.resolveModel(parent);
1039 } catch (UnresolvableModelException e) {
1040
1041 StringBuilder buffer = new StringBuilder(256);
1042 buffer.append("Non-resolvable parent POM");
1043 if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
1044 buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
1045 }
1046 if (childModel != problems.getRootModel()) {
1047 buffer.append(" for ").append(ModelProblemUtils.toId(childModel));
1048 }
1049 buffer.append(": ").append(e.getMessage());
1050 if (childModel.getProjectDirectory() != null) {
1051 if (parent.getRelativePath() == null || parent.getRelativePath().length() <= 0) {
1052 buffer.append(" and 'parent.relativePath' points at no local POM");
1053 } else {
1054 buffer.append(" and 'parent.relativePath' points at wrong local POM");
1055 }
1056 }
1057
1058 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
1059 .setMessage(buffer.toString())
1060 .setLocation(parent.getLocation(""))
1061 .setException(e));
1062 throw problems.newModelBuildingException();
1063 }
1064
1065 ModelBuildingRequest lenientRequest = request;
1066 if (request.getValidationLevel() > ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
1067 lenientRequest = new FilterModelBuildingRequest(request) {
1068 @Override
1069 public int getValidationLevel() {
1070 return ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
1071 }
1072 };
1073 }
1074
1075 Model parentModel = readModel(modelSource, null, lenientRequest, problems);
1076
1077 if (!parent.getVersion().equals(version)) {
1078 String rawChildModelVersion = childModel.getVersion();
1079
1080 if (rawChildModelVersion == null) {
1081
1082 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
1083 .setMessage("Version must be a constant")
1084 .setLocation(childModel.getLocation("")));
1085
1086 } else {
1087 if (rawChildVersionReferencesParent(rawChildModelVersion)) {
1088
1089 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
1090 .setMessage("Version must be a constant")
1091 .setLocation(childModel.getLocation("version")));
1092 }
1093 }
1094
1095
1096 }
1097
1098 ModelData parentData = new ModelData(
1099 modelSource, parentModel, parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
1100
1101 return parentData;
1102 }
1103
1104 private Model getSuperModel() {
1105 return superPomProvider.getSuperModel("4.0.0").clone();
1106 }
1107
1108 @SuppressWarnings("checkstyle:methodlength")
1109 private void importDependencyManagement(
1110 Model model,
1111 ModelBuildingRequest request,
1112 DefaultModelProblemCollector problems,
1113 Collection<String> importIds) {
1114 DependencyManagement depMgmt = model.getDependencyManagement();
1115
1116 if (depMgmt == null) {
1117 return;
1118 }
1119
1120 String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion();
1121
1122 importIds.add(importing);
1123
1124 final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver();
1125 final ModelResolver modelResolver = request.getModelResolver();
1126
1127 ModelBuildingRequest importRequest = null;
1128
1129 List<DependencyManagement> importMgmts = null;
1130
1131 for (Iterator<Dependency> it = depMgmt.getDependencies().iterator(); it.hasNext(); ) {
1132 Dependency dependency = it.next();
1133
1134 if (!"pom".equals(dependency.getType()) || !"import".equals(dependency.getScope())) {
1135 continue;
1136 }
1137
1138 it.remove();
1139
1140 String groupId = dependency.getGroupId();
1141 String artifactId = dependency.getArtifactId();
1142 String version = dependency.getVersion();
1143
1144 if (groupId == null || groupId.length() <= 0) {
1145 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1146 .setMessage("'dependencyManagement.dependencies.dependency.groupId' for "
1147 + dependency.getManagementKey() + " is missing.")
1148 .setLocation(dependency.getLocation("")));
1149 continue;
1150 }
1151 if (artifactId == null || artifactId.length() <= 0) {
1152 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1153 .setMessage("'dependencyManagement.dependencies.dependency.artifactId' for "
1154 + dependency.getManagementKey() + " is missing.")
1155 .setLocation(dependency.getLocation("")));
1156 continue;
1157 }
1158 if (version == null || version.length() <= 0) {
1159 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1160 .setMessage("'dependencyManagement.dependencies.dependency.version' for "
1161 + dependency.getManagementKey() + " is missing.")
1162 .setLocation(dependency.getLocation("")));
1163 continue;
1164 }
1165
1166 String imported = groupId + ':' + artifactId + ':' + version;
1167
1168 if (importIds.contains(imported)) {
1169 String message = "The dependencies of type=pom and with scope=import form a cycle: ";
1170 for (String modelId : importIds) {
1171 message += modelId + " -> ";
1172 }
1173 message += imported;
1174 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE).setMessage(message));
1175
1176 continue;
1177 }
1178
1179 DependencyManagement importMgmt =
1180 getCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT);
1181
1182 if (importMgmt == null) {
1183 if (workspaceResolver == null && modelResolver == null) {
1184 throw new NullPointerException(String.format(
1185 "request.workspaceModelResolver and request.modelResolver cannot be null"
1186 + " (parent POM %s and POM %s)",
1187 ModelProblemUtils.toId(groupId, artifactId, version),
1188 ModelProblemUtils.toSourceHint(model)));
1189 }
1190
1191 Model importModel = null;
1192 if (workspaceResolver != null) {
1193 try {
1194 importModel = workspaceResolver.resolveEffectiveModel(groupId, artifactId, version);
1195 } catch (UnresolvableModelException e) {
1196 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
1197 .setMessage(e.getMessage().toString())
1198 .setException(e));
1199 continue;
1200 }
1201 }
1202
1203
1204 if (importModel == null) {
1205 final ModelSource importSource;
1206 try {
1207 importSource = modelResolver.resolveModel(groupId, artifactId, version);
1208 } catch (UnresolvableModelException e) {
1209 StringBuilder buffer = new StringBuilder(256);
1210 buffer.append("Non-resolvable import POM");
1211 if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
1212 buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
1213 }
1214 buffer.append(": ").append(e.getMessage());
1215
1216 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1217 .setMessage(buffer.toString())
1218 .setLocation(dependency.getLocation(""))
1219 .setException(e));
1220 continue;
1221 }
1222
1223 if (importRequest == null) {
1224 importRequest = new DefaultModelBuildingRequest();
1225 importRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
1226 importRequest.setModelCache(request.getModelCache());
1227 importRequest.setSystemProperties(request.getSystemProperties());
1228 importRequest.setUserProperties(request.getUserProperties());
1229 importRequest.setLocationTracking(request.isLocationTracking());
1230 }
1231
1232 importRequest.setModelSource(importSource);
1233 importRequest.setModelResolver(modelResolver.newCopy());
1234
1235 final ModelBuildingResult importResult;
1236 try {
1237 importResult = build(importRequest, importIds);
1238 } catch (ModelBuildingException e) {
1239 problems.addAll(e.getProblems());
1240 continue;
1241 }
1242
1243 problems.addAll(importResult.getProblems());
1244
1245 importModel = importResult.getEffectiveModel();
1246 }
1247
1248 importMgmt = importModel.getDependencyManagement();
1249
1250 if (importMgmt == null) {
1251 importMgmt = new DependencyManagement();
1252 }
1253
1254 putCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt);
1255 }
1256
1257 if (importMgmts == null) {
1258 importMgmts = new ArrayList<>();
1259 }
1260
1261 importMgmts.add(importMgmt);
1262 }
1263
1264 importIds.remove(importing);
1265
1266 dependencyManagementImporter.importManagement(model, importMgmts, request, problems);
1267 }
1268
1269 private <T> void putCache(
1270 ModelCache modelCache, String groupId, String artifactId, String version, ModelCacheTag<T> tag, T data) {
1271 if (modelCache != null) {
1272 modelCache.put(groupId, artifactId, version, tag.getName(), tag.intoCache(data));
1273 }
1274 }
1275
1276 private <T> T getCache(
1277 ModelCache modelCache, String groupId, String artifactId, String version, ModelCacheTag<T> tag) {
1278 if (modelCache != null) {
1279 Object data = modelCache.get(groupId, artifactId, version, tag.getName());
1280 if (data != null) {
1281 return tag.fromCache(tag.getType().cast(data));
1282 }
1283 }
1284 return null;
1285 }
1286
1287 private void fireEvent(
1288 Model model,
1289 ModelBuildingRequest request,
1290 ModelProblemCollector problems,
1291 ModelBuildingEventCatapult catapult)
1292 throws ModelBuildingException {
1293 ModelBuildingListener listener = request.getModelBuildingListener();
1294
1295 if (listener != null) {
1296 ModelBuildingEvent event = new DefaultModelBuildingEvent(model, request, problems);
1297
1298 catapult.fire(listener, event);
1299 }
1300 }
1301
1302 private boolean containsCoordinates(String message, String groupId, String artifactId, String version) {
1303 return message != null
1304 && (groupId == null || message.contains(groupId))
1305 && (artifactId == null || message.contains(artifactId))
1306 && (version == null || message.contains(version));
1307 }
1308
1309 protected boolean hasModelErrors(ModelProblemCollectorExt problems) {
1310 if (problems instanceof DefaultModelProblemCollector collector) {
1311 return collector.hasErrors();
1312 } else {
1313
1314
1315 throw new IllegalStateException();
1316 }
1317 }
1318
1319 protected boolean hasFatalErrors(ModelProblemCollectorExt problems) {
1320 if (problems instanceof DefaultModelProblemCollector collector) {
1321 return collector.hasFatalErrors();
1322 } else {
1323
1324
1325 throw new IllegalStateException();
1326 }
1327 }
1328 }