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