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