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