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