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<>());
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 StringBuilder message = new StringBuilder("The parents form a cycle: ");
362 for (String modelId : parentIds) {
363 message.append(modelId);
364 message.append(" -> ");
365 }
366 message.append(parentData.getId());
367
368 problems.add(new ModelProblemCollectorRequest(ModelProblem.Severity.FATAL, ModelProblem.Version.BASE)
369 .setMessage(message.toString()));
370
371 throw problems.newModelBuildingException();
372 } else {
373 currentData = parentData;
374 }
375 }
376
377 problems.setSource(inputModel);
378 checkPluginVersions(lineage, request, problems);
379
380
381 assembleInheritance(lineage, request, problems);
382
383 Model resultModel = resultData.getModel();
384
385 problems.setSource(resultModel);
386 problems.setRootModel(resultModel);
387
388
389 resultModel = interpolateModel(resultModel, request, problems);
390 resultData.setModel(resultModel);
391
392 if (resultModel.getParent() != null) {
393 final ModelData parentData = lineage.get(1);
394 if (parentData.getVersion() == null || parentData.getVersion().contains("${")) {
395 final Model interpolatedParent = interpolateModel(parentData.getModel(), request, problems);
396
397 parentData.setVersion(interpolatedParent.getVersion());
398 }
399 }
400
401
402 modelUrlNormalizer.normalize(resultModel, request);
403
404
405 configureResolver(request.getModelResolver(), resultModel, problems, true);
406
407 resultData.setGroupId(resultModel.getGroupId());
408 resultData.setArtifactId(resultModel.getArtifactId());
409 resultData.setVersion(resultModel.getVersion());
410
411 result.setEffectiveModel(resultModel);
412
413 for (ModelData currentData : lineage) {
414 String modelId = (currentData != superData) ? currentData.getId() : "";
415
416 result.addModelId(modelId);
417 result.setActivePomProfiles(modelId, currentData.getActiveProfiles());
418 result.setRawModel(modelId, currentData.getRawModel());
419 }
420
421 if (!request.isTwoPhaseBuilding()) {
422 build(request, result, importIds);
423 }
424
425 return result;
426 }
427
428 @FunctionalInterface
429 private interface InterpolateString {
430 String apply(String s) throws InterpolationException;
431 }
432
433 private List<Profile> getInterpolatedProfiles(
434 Model rawModel, DefaultProfileActivationContext context, DefaultModelProblemCollector problems) {
435 List<Profile> interpolatedActivations = getProfiles(rawModel);
436
437 if (interpolatedActivations.isEmpty()) {
438 return Collections.emptyList();
439 }
440 RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
441
442 interpolator.addValueSource(new MapBasedValueSource(context.getProjectProperties()));
443 interpolator.addValueSource(new MapBasedValueSource(context.getUserProperties()));
444 interpolator.addValueSource(new MapBasedValueSource(context.getSystemProperties()));
445
446 class Interpolation {
447 final InputLocationTracker target;
448
449 final InterpolateString impl;
450
451 Interpolation(InputLocationTracker target, InterpolateString impl) {
452 this.target = target;
453 this.impl = impl;
454 }
455
456 void performFor(String value, String locationKey, Consumer<String> mutator) {
457 if (StringUtils.isEmpty(value)) {
458 return;
459 }
460 try {
461 mutator.accept(impl.apply(value));
462 } catch (InterpolationException e) {
463 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
464 .setMessage("Failed to interpolate value " + value + ": " + e.getMessage())
465 .setLocation(target.getLocation(locationKey))
466 .setException(e));
467 }
468 }
469 }
470 for (Profile profile : interpolatedActivations) {
471 Activation activation = profile.getActivation();
472 Optional<Activation> a = Optional.ofNullable(activation);
473 a.map(Activation::getFile).ifPresent(fa -> {
474 Interpolation nt =
475 new Interpolation(fa, s -> profileActivationFilePathInterpolator.interpolate(s, context));
476 nt.performFor(fa.getExists(), "exists", fa::setExists);
477 nt.performFor(fa.getMissing(), "missing", fa::setMissing);
478 });
479 a.map(Activation::getOs).ifPresent(oa -> {
480 Interpolation nt = new Interpolation(oa, interpolator::interpolate);
481 nt.performFor(oa.getArch(), "arch", oa::setArch);
482 nt.performFor(oa.getFamily(), "family", oa::setFamily);
483 nt.performFor(oa.getName(), "name", oa::setName);
484 nt.performFor(oa.getVersion(), "version", oa::setVersion);
485 });
486 a.map(Activation::getProperty).ifPresent(pa -> {
487 Interpolation nt = new Interpolation(pa, interpolator::interpolate);
488 nt.performFor(pa.getName(), "name", pa::setName);
489 nt.performFor(pa.getValue(), "value", pa::setValue);
490 });
491 a.map(Activation::getJdk)
492 .ifPresent(ja -> new Interpolation(activation, interpolator::interpolate)
493 .performFor(ja, "jdk", activation::setJdk));
494 }
495 return interpolatedActivations;
496 }
497
498 @Override
499 public ModelBuildingResult build(ModelBuildingRequest request, ModelBuildingResult result)
500 throws ModelBuildingException {
501 return build(request, result, new LinkedHashSet());
502 }
503
504 private ModelBuildingResult build(
505 ModelBuildingRequest request, ModelBuildingResult result, Collection<String> imports)
506 throws ModelBuildingException {
507
508 Model resultModel = result.getEffectiveModel();
509
510 DefaultModelProblemCollector problems = new DefaultModelProblemCollector(result);
511 problems.setSource(resultModel);
512 problems.setRootModel(resultModel);
513
514
515 modelPathTranslator.alignToBaseDirectory(resultModel, resultModel.getProjectDirectory(), request);
516
517
518 pluginManagementInjector.injectManagement(resultModel, request, problems);
519
520 fireEvent(resultModel, request, problems, ModelBuildingEventCatapult.BUILD_EXTENSIONS_ASSEMBLED);
521
522 if (request.isProcessPlugins()) {
523 if (lifecycleBindingsInjector == null) {
524 throw new IllegalStateException("lifecycle bindings injector is missing");
525 }
526
527
528 lifecycleBindingsInjector.injectLifecycleBindings(resultModel, request, problems);
529 }
530
531
532 importDependencyManagement(resultModel, request, problems, imports);
533
534
535 dependencyManagementInjector.injectManagement(resultModel, request, problems);
536
537 modelNormalizer.injectDefaultValues(resultModel, request, problems);
538
539 if (request.isProcessPlugins()) {
540
541 reportConfigurationExpander.expandPluginConfiguration(resultModel, request, problems);
542
543
544 reportingConverter.convertReporting(resultModel, request, problems);
545
546
547 pluginConfigurationExpander.expandPluginConfiguration(resultModel, request, problems);
548 }
549
550
551 modelValidator.validateEffectiveModel(resultModel, request, problems);
552
553 if (hasModelErrors(problems)) {
554 throw problems.newModelBuildingException();
555 }
556
557 return result;
558 }
559
560 @Override
561 public Result<? extends Model> buildRawModel(File pomFile, int validationLevel, boolean locationTracking) {
562 final ModelBuildingRequest request = new DefaultModelBuildingRequest()
563 .setValidationLevel(validationLevel)
564 .setLocationTracking(locationTracking);
565 final DefaultModelProblemCollector collector =
566 new DefaultModelProblemCollector(new DefaultModelBuildingResult());
567 try {
568 return newResult(readModel(null, pomFile, request, collector), collector.getProblems());
569 } catch (ModelBuildingException e) {
570 return error(collector.getProblems());
571 }
572 }
573
574 private Model readModel(
575 ModelSource modelSource, File pomFile, ModelBuildingRequest request, DefaultModelProblemCollector problems)
576 throws ModelBuildingException {
577 Model model;
578
579 if (modelSource == null) {
580 if (pomFile != null) {
581 modelSource = new FileModelSource(pomFile);
582 } else {
583 throw new NullPointerException("neither pomFile nor modelSource can be null");
584 }
585 }
586
587 problems.setSource(modelSource.getLocation());
588 try {
589 boolean strict = request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
590 InputSource source = request.isLocationTracking() ? new InputSource() : null;
591
592 Map<String, Object> options = new HashMap<>();
593 options.put(ModelProcessor.IS_STRICT, strict);
594 options.put(ModelProcessor.INPUT_SOURCE, source);
595 options.put(ModelProcessor.SOURCE, modelSource);
596
597 try {
598 model = modelProcessor.read(modelSource.getInputStream(), options);
599 } catch (ModelParseException e) {
600 if (!strict) {
601 throw e;
602 }
603
604 options.put(ModelProcessor.IS_STRICT, Boolean.FALSE);
605
606 try {
607 model = modelProcessor.read(modelSource.getInputStream(), options);
608 } catch (ModelParseException ne) {
609
610 throw e;
611 }
612
613 if (pomFile != null) {
614 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.V20)
615 .setMessage("Malformed POM " + modelSource.getLocation() + ": " + e.getMessage())
616 .setException(e));
617 } else {
618 problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.V20)
619 .setMessage("Malformed POM " + modelSource.getLocation() + ": " + e.getMessage())
620 .setException(e));
621 }
622 }
623
624 if (source != null) {
625 source.setModelId(ModelProblemUtils.toId(model));
626 source.setLocation(modelSource.getLocation());
627 }
628 } catch (ModelParseException e) {
629 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
630 .setMessage("Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage())
631 .setException(e));
632 throw problems.newModelBuildingException();
633 } catch (IOException e) {
634 String msg = e.getMessage();
635 if (msg == null || msg.length() <= 0) {
636
637 if (e.getClass().getName().endsWith("MalformedInputException")) {
638 msg = "Some input bytes do not match the file encoding.";
639 } else {
640 msg = e.getClass().getSimpleName();
641 }
642 }
643 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
644 .setMessage("Non-readable POM " + modelSource.getLocation() + ": " + msg)
645 .setException(e));
646 throw problems.newModelBuildingException();
647 }
648
649 model.setPomFile(pomFile);
650
651 problems.setSource(model);
652 modelValidator.validateRawModel(model, request, problems);
653
654 if (hasFatalErrors(problems)) {
655 throw problems.newModelBuildingException();
656 }
657
658 return model;
659 }
660
661 private DefaultProfileActivationContext getProfileActivationContext(ModelBuildingRequest request, Model rawModel) {
662 DefaultProfileActivationContext context = new DefaultProfileActivationContext();
663
664 context.setActiveProfileIds(request.getActiveProfileIds());
665 context.setInactiveProfileIds(request.getInactiveProfileIds());
666 context.setSystemProperties(request.getSystemProperties());
667
668 Properties userProperties = request.getUserProperties();
669 userProperties.computeIfAbsent(
670 (Object) ProfileActivationContext.PROPERTY_NAME_PACKAGING, (p) -> (Object) rawModel.getPackaging());
671 context.setUserProperties(userProperties);
672 context.setProjectDirectory(
673 (request.getPomFile() != null) ? request.getPomFile().getParentFile() : null);
674
675 return context;
676 }
677
678 private void configureResolver(ModelResolver modelResolver, Model model, DefaultModelProblemCollector problems) {
679 configureResolver(modelResolver, model, problems, false);
680 }
681
682 private void configureResolver(
683 ModelResolver modelResolver,
684 Model model,
685 DefaultModelProblemCollector problems,
686 boolean replaceRepositories) {
687 if (modelResolver == null) {
688 return;
689 }
690
691 problems.setSource(model);
692
693 List<Repository> repositories = model.getRepositories();
694
695 for (Repository repository : repositories) {
696 try {
697 modelResolver.addRepository(repository, replaceRepositories);
698 } catch (InvalidRepositoryException e) {
699 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
700 .setMessage("Invalid repository " + repository.getId() + ": " + e.getMessage())
701 .setLocation(repository.getLocation(""))
702 .setException(e));
703 }
704 }
705 }
706
707 private void checkPluginVersions(
708 List<ModelData> lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
709 if (request.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
710 return;
711 }
712
713 Map<String, Plugin> plugins = new HashMap<>();
714 Map<String, String> versions = new HashMap<>();
715 Map<String, String> managedVersions = new HashMap<>();
716
717 for (int i = lineage.size() - 1; i >= 0; i--) {
718 Model model = lineage.get(i).getModel();
719 Build build = model.getBuild();
720 if (build != null) {
721 for (Plugin plugin : build.getPlugins()) {
722 String key = plugin.getKey();
723 if (versions.get(key) == null) {
724 versions.put(key, plugin.getVersion());
725 plugins.put(key, plugin);
726 }
727 }
728 PluginManagement mgmt = build.getPluginManagement();
729 if (mgmt != null) {
730 for (Plugin plugin : mgmt.getPlugins()) {
731 String key = plugin.getKey();
732 if (managedVersions.get(key) == null) {
733 managedVersions.put(key, plugin.getVersion());
734 }
735 }
736 }
737 }
738 }
739
740 for (String key : versions.keySet()) {
741 if (versions.get(key) == null && managedVersions.get(key) == null) {
742 InputLocation location = plugins.get(key).getLocation("");
743 problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.V20)
744 .setMessage("'build.plugins.plugin.version' for " + key + " is missing.")
745 .setLocation(location));
746 }
747 }
748 }
749
750 private void assembleInheritance(
751 List<ModelData> lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
752 for (int i = lineage.size() - 2; i >= 0; i--) {
753 Model parent = lineage.get(i + 1).getModel();
754 Model child = lineage.get(i).getModel();
755 inheritanceAssembler.assembleModelInheritance(child, parent, request, problems);
756 }
757 }
758
759 private List<Profile> getProfiles(Model model) {
760 ArrayList<Profile> profiles = new ArrayList<>();
761 for (Profile profile : model.getProfiles()) {
762 profile = profile.clone();
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);
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())
800 .forEach(i -> interpolatedProfiles
801 .get(i)
802 .setActivation(originalProfiles.get(i).getActivation()));
803
804 return interpolatedModel;
805 }
806
807 private ModelData readParent(
808 Model childModel,
809 ModelSource childSource,
810 ModelBuildingRequest request,
811 DefaultModelProblemCollector problems)
812 throws ModelBuildingException {
813 ModelData parentData;
814
815 Parent parent = childModel.getParent();
816
817 if (parent != null) {
818 String groupId = parent.getGroupId();
819 String artifactId = parent.getArtifactId();
820 String version = parent.getVersion();
821
822 parentData = getCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW);
823
824 if (parentData == null) {
825 parentData = readParentLocally(childModel, childSource, request, problems);
826
827 if (parentData == null) {
828 parentData = readParentExternally(childModel, request, problems);
829 }
830
831 putCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW, parentData);
832 } else {
833
834
835
836
837
838
839
840 File pomFile = parentData.getModel().getPomFile();
841 if (pomFile != null) {
842 FileModelSource pomSource = new FileModelSource(pomFile);
843 ModelSource expectedParentSource = getParentPomFile(childModel, childSource);
844
845 if (expectedParentSource == null
846 || (expectedParentSource instanceof ModelSource2
847 && !pomSource.equals(expectedParentSource))) {
848 parentData = readParentExternally(childModel, request, problems);
849 }
850 }
851 }
852
853 Model parentModel = parentData.getModel();
854
855 if (!"pom".equals(parentModel.getPackaging())) {
856 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
857 .setMessage("Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint(parentModel)
858 + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"")
859 .setLocation(parentModel.getLocation("packaging")));
860 }
861 } else {
862 parentData = null;
863 }
864
865 return parentData;
866 }
867
868 private ModelData readParentLocally(
869 Model childModel,
870 ModelSource childSource,
871 ModelBuildingRequest request,
872 DefaultModelProblemCollector problems)
873 throws ModelBuildingException {
874 final Parent parent = childModel.getParent();
875 final ModelSource candidateSource;
876 final Model candidateModel;
877 final WorkspaceModelResolver resolver = request.getWorkspaceModelResolver();
878 if (resolver == null) {
879 candidateSource = getParentPomFile(childModel, childSource);
880
881 if (candidateSource == null) {
882 return null;
883 }
884
885 File pomFile = null;
886 if (candidateSource instanceof FileModelSource source) {
887 pomFile = source.getPomFile();
888 }
889
890 candidateModel = readModel(candidateSource, pomFile, request, problems);
891 } else {
892 try {
893 candidateModel =
894 resolver.resolveRawModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
895 } catch (UnresolvableModelException e) {
896 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
897 .setMessage(e.getMessage())
898 .setLocation(parent.getLocation(""))
899 .setException(e));
900 throw problems.newModelBuildingException();
901 }
902 if (candidateModel == null) {
903 return null;
904 }
905 candidateSource = new FileModelSource(candidateModel.getPomFile());
906 }
907
908
909
910
911
912
913
914 String groupId = candidateModel.getGroupId();
915 if (groupId == null && candidateModel.getParent() != null) {
916 groupId = candidateModel.getParent().getGroupId();
917 }
918 String artifactId = candidateModel.getArtifactId();
919 String version = candidateModel.getVersion();
920 if (version == null && candidateModel.getParent() != null) {
921 version = candidateModel.getParent().getVersion();
922 }
923
924 if (groupId == null
925 || !groupId.equals(parent.getGroupId())
926 || artifactId == null
927 || !artifactId.equals(parent.getArtifactId())) {
928 StringBuilder buffer = new StringBuilder(256);
929 buffer.append("'parent.relativePath'");
930 if (childModel != problems.getRootModel()) {
931 buffer.append(" of POM ").append(ModelProblemUtils.toSourceHint(childModel));
932 }
933 buffer.append(" points at ").append(groupId).append(':').append(artifactId);
934 buffer.append(" instead of ").append(parent.getGroupId()).append(':');
935 buffer.append(parent.getArtifactId()).append(", please verify your project structure");
936
937 problems.setSource(childModel);
938 problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.BASE)
939 .setMessage(buffer.toString())
940 .setLocation(parent.getLocation("")));
941 return null;
942 }
943 if (version != null && parent.getVersion() != null && !version.equals(parent.getVersion())) {
944 try {
945 VersionRange parentRange = VersionRange.createFromVersionSpec(parent.getVersion());
946 if (!parentRange.hasRestrictions()) {
947
948 return null;
949 }
950 if (!parentRange.containsVersion(new DefaultArtifactVersion(version))) {
951
952 return null;
953 }
954
955
956 String rawChildModelVersion = childModel.getVersion();
957
958 if (rawChildModelVersion == null) {
959
960 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
961 .setMessage("Version must be a constant")
962 .setLocation(childModel.getLocation("")));
963
964 } else {
965 if (rawChildVersionReferencesParent(rawChildModelVersion)) {
966
967 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
968 .setMessage("Version must be a constant")
969 .setLocation(childModel.getLocation("version")));
970 }
971 }
972
973
974 } catch (InvalidVersionSpecificationException e) {
975
976 return null;
977 }
978 }
979
980
981
982
983
984
985
986
987
988
989 ModelData parentData = new ModelData(candidateSource, candidateModel, groupId, artifactId, version);
990
991 return parentData;
992 }
993
994 private boolean rawChildVersionReferencesParent(String rawChildModelVersion) {
995 return rawChildModelVersion.equals("${pom.version}")
996 || rawChildModelVersion.equals("${project.version}")
997 || rawChildModelVersion.equals("${pom.parent.version}")
998 || rawChildModelVersion.equals("${project.parent.version}");
999 }
1000
1001 private ModelSource getParentPomFile(Model childModel, ModelSource source) {
1002 if (!(source instanceof ModelSource2)) {
1003 return null;
1004 }
1005
1006 String parentPath = childModel.getParent().getRelativePath();
1007 if (parentPath == null) {
1008 parentPath = "../pom.xml";
1009 }
1010
1011 if (parentPath.length() <= 0) {
1012 return null;
1013 }
1014
1015 return ((ModelSource2) source).getRelatedSource(parentPath);
1016 }
1017
1018 private ModelData readParentExternally(
1019 Model childModel, ModelBuildingRequest request, DefaultModelProblemCollector problems)
1020 throws ModelBuildingException {
1021 problems.setSource(childModel);
1022
1023 Parent parent = childModel.getParent().clone();
1024
1025 String groupId = parent.getGroupId();
1026 String artifactId = parent.getArtifactId();
1027 String version = parent.getVersion();
1028
1029 ModelResolver modelResolver = request.getModelResolver();
1030 Objects.requireNonNull(
1031 modelResolver,
1032 String.format(
1033 "request.modelResolver cannot be null (parent POM %s and POM %s)",
1034 ModelProblemUtils.toId(groupId, artifactId, version),
1035 ModelProblemUtils.toSourceHint(childModel)));
1036
1037 ModelSource modelSource;
1038 try {
1039 modelSource = modelResolver.resolveModel(parent);
1040 } catch (UnresolvableModelException e) {
1041
1042 StringBuilder buffer = new StringBuilder(256);
1043 buffer.append("Non-resolvable parent POM");
1044 if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
1045 buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
1046 }
1047 if (childModel != problems.getRootModel()) {
1048 buffer.append(" for ").append(ModelProblemUtils.toId(childModel));
1049 }
1050 buffer.append(": ").append(e.getMessage());
1051 if (childModel.getProjectDirectory() != null) {
1052 if (parent.getRelativePath() == null || parent.getRelativePath().length() <= 0) {
1053 buffer.append(" and 'parent.relativePath' points at no local POM");
1054 } else {
1055 buffer.append(" and 'parent.relativePath' points at wrong local POM");
1056 }
1057 }
1058
1059 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
1060 .setMessage(buffer.toString())
1061 .setLocation(parent.getLocation(""))
1062 .setException(e));
1063 throw problems.newModelBuildingException();
1064 }
1065
1066 ModelBuildingRequest lenientRequest = request;
1067 if (request.getValidationLevel() > ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
1068 lenientRequest = new FilterModelBuildingRequest(request) {
1069 @Override
1070 public int getValidationLevel() {
1071 return ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
1072 }
1073 };
1074 }
1075
1076 Model parentModel = readModel(modelSource, null, lenientRequest, problems);
1077
1078 if (!parent.getVersion().equals(version)) {
1079 String rawChildModelVersion = childModel.getVersion();
1080
1081 if (rawChildModelVersion == null) {
1082
1083 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
1084 .setMessage("Version must be a constant")
1085 .setLocation(childModel.getLocation("")));
1086
1087 } else {
1088 if (rawChildVersionReferencesParent(rawChildModelVersion)) {
1089
1090 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
1091 .setMessage("Version must be a constant")
1092 .setLocation(childModel.getLocation("version")));
1093 }
1094 }
1095
1096
1097 }
1098
1099 ModelData parentData = new ModelData(
1100 modelSource, parentModel, parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
1101
1102 return parentData;
1103 }
1104
1105 private Model getSuperModel() {
1106 return superPomProvider.getSuperModel("4.0.0").clone();
1107 }
1108
1109 @SuppressWarnings("checkstyle:methodlength")
1110 private void importDependencyManagement(
1111 Model model,
1112 ModelBuildingRequest request,
1113 DefaultModelProblemCollector problems,
1114 Collection<String> importIds) {
1115 DependencyManagement depMgmt = model.getDependencyManagement();
1116
1117 if (depMgmt == null) {
1118 return;
1119 }
1120
1121 String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion();
1122
1123 importIds.add(importing);
1124
1125 final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver();
1126 final ModelResolver modelResolver = request.getModelResolver();
1127
1128 ModelBuildingRequest importRequest = null;
1129
1130 List<DependencyManagement> importMgmts = null;
1131
1132 for (Iterator<Dependency> it = depMgmt.getDependencies().iterator(); it.hasNext(); ) {
1133 Dependency dependency = it.next();
1134
1135 if (!"pom".equals(dependency.getType()) || !"import".equals(dependency.getScope())) {
1136 continue;
1137 }
1138
1139 it.remove();
1140
1141 String groupId = dependency.getGroupId();
1142 String artifactId = dependency.getArtifactId();
1143 String version = dependency.getVersion();
1144
1145 if (groupId == null || groupId.length() <= 0) {
1146 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1147 .setMessage("'dependencyManagement.dependencies.dependency.groupId' for "
1148 + dependency.getManagementKey() + " is missing.")
1149 .setLocation(dependency.getLocation("")));
1150 continue;
1151 }
1152 if (artifactId == null || artifactId.length() <= 0) {
1153 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1154 .setMessage("'dependencyManagement.dependencies.dependency.artifactId' for "
1155 + dependency.getManagementKey() + " is missing.")
1156 .setLocation(dependency.getLocation("")));
1157 continue;
1158 }
1159 if (version == null || version.length() <= 0) {
1160 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1161 .setMessage("'dependencyManagement.dependencies.dependency.version' for "
1162 + dependency.getManagementKey() + " is missing.")
1163 .setLocation(dependency.getLocation("")));
1164 continue;
1165 }
1166
1167 String imported = groupId + ':' + artifactId + ':' + version;
1168
1169 if (importIds.contains(imported)) {
1170 StringBuilder message =
1171 new StringBuilder("The dependencies of type=pom and with scope=import form a cycle: ");
1172 for (String modelId : importIds) {
1173 message.append(modelId);
1174 message.append(" -> ");
1175 }
1176 message.append(imported);
1177 problems.add(
1178 new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE).setMessage(message.toString()));
1179
1180 continue;
1181 }
1182
1183 DependencyManagement importMgmt =
1184 getCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT);
1185
1186 if (importMgmt == null) {
1187 if (workspaceResolver == null && modelResolver == null) {
1188 throw new NullPointerException(String.format(
1189 "request.workspaceModelResolver and request.modelResolver cannot be null"
1190 + " (parent POM %s and POM %s)",
1191 ModelProblemUtils.toId(groupId, artifactId, version),
1192 ModelProblemUtils.toSourceHint(model)));
1193 }
1194
1195 Model importModel = null;
1196 if (workspaceResolver != null) {
1197 try {
1198 importModel = workspaceResolver.resolveEffectiveModel(groupId, artifactId, version);
1199 } catch (UnresolvableModelException e) {
1200 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
1201 .setMessage(e.getMessage())
1202 .setException(e));
1203 continue;
1204 }
1205 }
1206
1207
1208 if (importModel == null) {
1209 final ModelSource importSource;
1210 try {
1211 importSource = modelResolver.resolveModel(groupId, artifactId, version);
1212 } catch (UnresolvableModelException e) {
1213 StringBuilder buffer = new StringBuilder(256);
1214 buffer.append("Non-resolvable import POM");
1215 if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
1216 buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
1217 }
1218 buffer.append(": ").append(e.getMessage());
1219
1220 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1221 .setMessage(buffer.toString())
1222 .setLocation(dependency.getLocation(""))
1223 .setException(e));
1224 continue;
1225 }
1226
1227 if (importRequest == null) {
1228 importRequest = new DefaultModelBuildingRequest();
1229 importRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
1230 importRequest.setModelCache(request.getModelCache());
1231 importRequest.setSystemProperties(request.getSystemProperties());
1232 importRequest.setUserProperties(request.getUserProperties());
1233 importRequest.setLocationTracking(request.isLocationTracking());
1234 }
1235
1236 importRequest.setModelSource(importSource);
1237 importRequest.setModelResolver(modelResolver.newCopy());
1238
1239 final ModelBuildingResult importResult;
1240 try {
1241 importResult = build(importRequest, importIds);
1242 } catch (ModelBuildingException e) {
1243 problems.addAll(e.getProblems());
1244 continue;
1245 }
1246
1247 problems.addAll(importResult.getProblems());
1248
1249 importModel = importResult.getEffectiveModel();
1250 }
1251
1252 importMgmt = importModel.getDependencyManagement();
1253
1254 if (importMgmt == null) {
1255 importMgmt = new DependencyManagement();
1256 }
1257
1258 putCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt);
1259 }
1260
1261 if (importMgmts == null) {
1262 importMgmts = new ArrayList<>();
1263 }
1264
1265 importMgmts.add(importMgmt);
1266 }
1267
1268 importIds.remove(importing);
1269
1270 dependencyManagementImporter.importManagement(model, importMgmts, request, problems);
1271 }
1272
1273 private <T> void putCache(
1274 ModelCache modelCache, String groupId, String artifactId, String version, ModelCacheTag<T> tag, T data) {
1275 if (modelCache != null) {
1276 modelCache.put(groupId, artifactId, version, tag.getName(), tag.intoCache(data));
1277 }
1278 }
1279
1280 private <T> T getCache(
1281 ModelCache modelCache, String groupId, String artifactId, String version, ModelCacheTag<T> tag) {
1282 if (modelCache != null) {
1283 Object data = modelCache.get(groupId, artifactId, version, tag.getName());
1284 if (data != null) {
1285 return tag.fromCache(tag.getType().cast(data));
1286 }
1287 }
1288 return null;
1289 }
1290
1291 private void fireEvent(
1292 Model model,
1293 ModelBuildingRequest request,
1294 ModelProblemCollector problems,
1295 ModelBuildingEventCatapult catapult) {
1296 ModelBuildingListener listener = request.getModelBuildingListener();
1297
1298 if (listener != null) {
1299 ModelBuildingEvent event = new DefaultModelBuildingEvent(model, request, problems);
1300
1301 catapult.fire(listener, event);
1302 }
1303 }
1304
1305 private boolean containsCoordinates(String message, String groupId, String artifactId, String version) {
1306 return message != null
1307 && (groupId == null || message.contains(groupId))
1308 && (artifactId == null || message.contains(artifactId))
1309 && (version == null || message.contains(version));
1310 }
1311
1312 protected boolean hasModelErrors(ModelProblemCollectorExt problems) {
1313 if (problems instanceof DefaultModelProblemCollector collector) {
1314 return collector.hasErrors();
1315 } else {
1316
1317
1318 throw new IllegalStateException();
1319 }
1320 }
1321
1322 protected boolean hasFatalErrors(ModelProblemCollectorExt problems) {
1323 if (problems instanceof DefaultModelProblemCollector collector) {
1324 return collector.hasFatalErrors();
1325 } else {
1326
1327
1328 throw new IllegalStateException();
1329 }
1330 }
1331 }