1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.model.building;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.File;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.LinkedHashSet;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Objects;
36 import java.util.Optional;
37 import java.util.Properties;
38 import java.util.function.Consumer;
39 import java.util.stream.IntStream;
40
41 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
42 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
43 import org.apache.maven.artifact.versioning.VersionRange;
44 import org.apache.maven.model.Activation;
45 import org.apache.maven.model.Build;
46 import org.apache.maven.model.Dependency;
47 import org.apache.maven.model.DependencyManagement;
48 import org.apache.maven.model.InputLocation;
49 import org.apache.maven.model.InputLocationTracker;
50 import org.apache.maven.model.InputSource;
51 import org.apache.maven.model.Model;
52 import org.apache.maven.model.Parent;
53 import org.apache.maven.model.Plugin;
54 import org.apache.maven.model.PluginManagement;
55 import org.apache.maven.model.Profile;
56 import org.apache.maven.model.Repository;
57 import org.apache.maven.model.building.ModelProblem.Severity;
58 import org.apache.maven.model.building.ModelProblem.Version;
59 import org.apache.maven.model.composition.DependencyManagementImporter;
60 import org.apache.maven.model.inheritance.InheritanceAssembler;
61 import org.apache.maven.model.interpolation.ModelInterpolator;
62 import org.apache.maven.model.io.ModelParseException;
63 import org.apache.maven.model.management.DependencyManagementInjector;
64 import org.apache.maven.model.management.PluginManagementInjector;
65 import org.apache.maven.model.normalization.ModelNormalizer;
66 import org.apache.maven.model.path.ModelPathTranslator;
67 import org.apache.maven.model.path.ModelUrlNormalizer;
68 import org.apache.maven.model.path.ProfileActivationFilePathInterpolator;
69 import org.apache.maven.model.plugin.LifecycleBindingsInjector;
70 import org.apache.maven.model.plugin.PluginConfigurationExpander;
71 import org.apache.maven.model.plugin.ReportConfigurationExpander;
72 import org.apache.maven.model.plugin.ReportingConverter;
73 import org.apache.maven.model.profile.DefaultProfileActivationContext;
74 import org.apache.maven.model.profile.ProfileActivationContext;
75 import org.apache.maven.model.profile.ProfileInjector;
76 import org.apache.maven.model.profile.ProfileSelector;
77 import org.apache.maven.model.resolution.InvalidRepositoryException;
78 import org.apache.maven.model.resolution.ModelResolver;
79 import org.apache.maven.model.resolution.UnresolvableModelException;
80 import org.apache.maven.model.resolution.WorkspaceModelResolver;
81 import org.apache.maven.model.superpom.SuperPomProvider;
82 import org.apache.maven.model.validation.ModelValidator;
83 import org.codehaus.plexus.interpolation.InterpolationException;
84 import org.codehaus.plexus.interpolation.MapBasedValueSource;
85 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
86 import org.codehaus.plexus.interpolation.StringSearchInterpolator;
87 import org.codehaus.plexus.util.StringUtils;
88 import org.eclipse.sisu.Nullable;
89
90 import static org.apache.maven.model.building.Result.error;
91 import static org.apache.maven.model.building.Result.newResult;
92
93
94
95
96 @Named
97 @Singleton
98 public class DefaultModelBuilder implements ModelBuilder {
99 @Inject
100 private ModelProcessor modelProcessor;
101
102 @Inject
103 private ModelValidator modelValidator;
104
105 @Inject
106 private ModelNormalizer modelNormalizer;
107
108 @Inject
109 private ModelInterpolator modelInterpolator;
110
111 @Inject
112 private ModelPathTranslator modelPathTranslator;
113
114 @Inject
115 private ModelUrlNormalizer modelUrlNormalizer;
116
117 @Inject
118 private SuperPomProvider superPomProvider;
119
120 @Inject
121 private InheritanceAssembler inheritanceAssembler;
122
123 @Inject
124 private ProfileSelector profileSelector;
125
126 @Inject
127 private ProfileInjector profileInjector;
128
129 @Inject
130 private PluginManagementInjector pluginManagementInjector;
131
132 @Inject
133 private DependencyManagementInjector dependencyManagementInjector;
134
135 @Inject
136 private DependencyManagementImporter dependencyManagementImporter;
137
138 @Inject
139 @Nullable
140 private LifecycleBindingsInjector lifecycleBindingsInjector;
141
142 @Inject
143 private PluginConfigurationExpander pluginConfigurationExpander;
144
145 @Inject
146 private ReportConfigurationExpander reportConfigurationExpander;
147
148 @Inject
149 private ReportingConverter reportingConverter;
150
151 @Inject
152 private ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator;
153
154 public DefaultModelBuilder setModelProcessor(ModelProcessor modelProcessor) {
155 this.modelProcessor = modelProcessor;
156 return this;
157 }
158
159 public DefaultModelBuilder setModelValidator(ModelValidator modelValidator) {
160 this.modelValidator = modelValidator;
161 return this;
162 }
163
164 public DefaultModelBuilder setModelNormalizer(ModelNormalizer modelNormalizer) {
165 this.modelNormalizer = modelNormalizer;
166 return this;
167 }
168
169 public DefaultModelBuilder setModelInterpolator(ModelInterpolator modelInterpolator) {
170 this.modelInterpolator = modelInterpolator;
171 return this;
172 }
173
174 public DefaultModelBuilder setModelPathTranslator(ModelPathTranslator modelPathTranslator) {
175 this.modelPathTranslator = modelPathTranslator;
176 return this;
177 }
178
179 public DefaultModelBuilder setModelUrlNormalizer(ModelUrlNormalizer modelUrlNormalizer) {
180 this.modelUrlNormalizer = modelUrlNormalizer;
181 return this;
182 }
183
184 public DefaultModelBuilder setSuperPomProvider(SuperPomProvider superPomProvider) {
185 this.superPomProvider = superPomProvider;
186 return this;
187 }
188
189 public DefaultModelBuilder setProfileSelector(ProfileSelector profileSelector) {
190 this.profileSelector = profileSelector;
191 return this;
192 }
193
194 public DefaultModelBuilder setProfileInjector(ProfileInjector profileInjector) {
195 this.profileInjector = profileInjector;
196 return this;
197 }
198
199 public DefaultModelBuilder setInheritanceAssembler(InheritanceAssembler inheritanceAssembler) {
200 this.inheritanceAssembler = inheritanceAssembler;
201 return this;
202 }
203
204 public DefaultModelBuilder setDependencyManagementImporter(DependencyManagementImporter depMgmtImporter) {
205 this.dependencyManagementImporter = depMgmtImporter;
206 return this;
207 }
208
209 public DefaultModelBuilder setDependencyManagementInjector(DependencyManagementInjector depMgmtInjector) {
210 this.dependencyManagementInjector = depMgmtInjector;
211 return this;
212 }
213
214 public DefaultModelBuilder setLifecycleBindingsInjector(LifecycleBindingsInjector lifecycleBindingsInjector) {
215 this.lifecycleBindingsInjector = lifecycleBindingsInjector;
216 return this;
217 }
218
219 public DefaultModelBuilder setPluginConfigurationExpander(PluginConfigurationExpander pluginConfigurationExpander) {
220 this.pluginConfigurationExpander = pluginConfigurationExpander;
221 return this;
222 }
223
224 public DefaultModelBuilder setPluginManagementInjector(PluginManagementInjector pluginManagementInjector) {
225 this.pluginManagementInjector = pluginManagementInjector;
226 return this;
227 }
228
229 public DefaultModelBuilder setReportConfigurationExpander(ReportConfigurationExpander reportConfigurationExpander) {
230 this.reportConfigurationExpander = reportConfigurationExpander;
231 return this;
232 }
233
234 public DefaultModelBuilder setReportingConverter(ReportingConverter reportingConverter) {
235 this.reportingConverter = reportingConverter;
236 return this;
237 }
238
239 public DefaultModelBuilder setProfileActivationFilePathInterpolator(
240 ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator) {
241 this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator;
242 return this;
243 }
244
245 @SuppressWarnings("checkstyle:methodlength")
246 @Override
247 public ModelBuildingResult build(ModelBuildingRequest request) throws ModelBuildingException {
248 return build(request, new LinkedHashSet<String>());
249 }
250
251 @SuppressWarnings("checkstyle:methodlength")
252 protected ModelBuildingResult build(ModelBuildingRequest request, Collection<String> importIds)
253 throws ModelBuildingException {
254
255 DefaultModelBuildingResult result = new DefaultModelBuildingResult();
256
257 DefaultModelProblemCollector problems = new DefaultModelProblemCollector(result);
258
259
260 Model inputModel = request.getRawModel();
261 if (inputModel == null) {
262 inputModel = readModel(request.getModelSource(), request.getPomFile(), request, problems);
263 }
264
265
266 DefaultProfileActivationContext profileActivationContext = getProfileActivationContext(request, inputModel);
267
268 problems.setSource("(external profiles)");
269 List<Profile> activeExternalProfiles =
270 profileSelector.getActiveProfiles(request.getProfiles(), profileActivationContext, problems);
271
272 result.setActiveExternalProfiles(activeExternalProfiles);
273
274 if (!activeExternalProfiles.isEmpty()) {
275 Properties profileProps = new Properties();
276 for (Profile profile : activeExternalProfiles) {
277 profileProps.putAll(profile.getProperties());
278 }
279 profileProps.putAll(profileActivationContext.getUserProperties());
280 profileActivationContext.setUserProperties(profileProps);
281 }
282
283 problems.setRootModel(inputModel);
284
285 ModelData resultData = new ModelData(request.getModelSource(), inputModel);
286 ModelData superData = new ModelData(null, getSuperModel());
287
288 Collection<String> parentIds = new LinkedHashSet<>();
289 List<ModelData> lineage = new ArrayList<>();
290
291 for (ModelData currentData = resultData; currentData != null; ) {
292 lineage.add(currentData);
293
294 Model rawModel = currentData.getModel();
295 currentData.setRawModel(rawModel);
296
297 Model tmpModel = rawModel.clone();
298 currentData.setModel(tmpModel);
299
300 problems.setSource(tmpModel);
301
302
303 modelNormalizer.mergeDuplicates(tmpModel, request, problems);
304
305 profileActivationContext.setProjectProperties(tmpModel.getProperties());
306
307 List<Profile> interpolatedProfiles = getInterpolatedProfiles(rawModel, profileActivationContext, problems);
308 tmpModel.setProfiles(interpolatedProfiles);
309
310 List<Profile> activePomProfiles =
311 profileSelector.getActiveProfiles(tmpModel.getProfiles(), profileActivationContext, problems);
312
313 List<Profile> rawProfiles = new ArrayList<>();
314 for (Profile activePomProfile : activePomProfiles) {
315 rawProfiles.add(rawModel.getProfiles().get(interpolatedProfiles.indexOf(activePomProfile)));
316 }
317 currentData.setActiveProfiles(rawProfiles);
318
319
320 for (Profile activeProfile : activePomProfiles) {
321 profileInjector.injectProfile(tmpModel, activeProfile, request, problems);
322 }
323
324 if (currentData == resultData) {
325 for (Profile activeProfile : activeExternalProfiles) {
326 profileInjector.injectProfile(tmpModel, activeProfile, request, problems);
327 }
328 }
329
330 if (currentData == superData) {
331 break;
332 }
333
334 configureResolver(request.getModelResolver(), tmpModel, problems);
335
336 ModelData parentData = readParent(tmpModel, currentData.getSource(), request, problems);
337
338 if (parentData == null) {
339 currentData = superData;
340 } else if (currentData == resultData) {
341 currentData.setGroupId(
342 currentData.getRawModel().getGroupId() == null
343 ? parentData.getGroupId()
344 : currentData.getRawModel().getGroupId());
345
346 currentData.setVersion(
347 currentData.getRawModel().getVersion() == null
348 ? parentData.getVersion()
349 : currentData.getRawModel().getVersion());
350
351 currentData.setArtifactId(currentData.getRawModel().getArtifactId());
352 parentIds.add(currentData.getId());
353
354 currentData.setGroupId(null);
355 currentData.setArtifactId(null);
356 currentData.setVersion(null);
357 currentData = parentData;
358 } else if (!parentIds.add(parentData.getId())) {
359 String message = "The parents form a cycle: ";
360 for (String modelId : parentIds) {
361 message += modelId + " -> ";
362 }
363 message += parentData.getId();
364
365 problems.add(new ModelProblemCollectorRequest(ModelProblem.Severity.FATAL, ModelProblem.Version.BASE)
366 .setMessage(message));
367
368 throw problems.newModelBuildingException();
369 } else {
370 currentData = parentData;
371 }
372 }
373
374 problems.setSource(inputModel);
375 checkPluginVersions(lineage, request, problems);
376
377
378 assembleInheritance(lineage, request, problems);
379
380 Model resultModel = resultData.getModel();
381
382 problems.setSource(resultModel);
383 problems.setRootModel(resultModel);
384
385
386 resultModel = interpolateModel(resultModel, request, problems);
387 resultData.setModel(resultModel);
388
389 if (resultModel.getParent() != null) {
390 final ModelData parentData = lineage.get(1);
391 if (parentData.getVersion() == null || parentData.getVersion().contains("${")) {
392 final Model interpolatedParent = interpolateModel(parentData.getModel(), request, problems);
393
394 parentData.setVersion(interpolatedParent.getVersion());
395 }
396 }
397
398
399 modelUrlNormalizer.normalize(resultModel, request);
400
401
402 configureResolver(request.getModelResolver(), resultModel, problems, true);
403
404 resultData.setGroupId(resultModel.getGroupId());
405 resultData.setArtifactId(resultModel.getArtifactId());
406 resultData.setVersion(resultModel.getVersion());
407
408 result.setEffectiveModel(resultModel);
409
410 for (ModelData currentData : lineage) {
411 String modelId = (currentData != superData) ? currentData.getId() : "";
412
413 result.addModelId(modelId);
414 result.setActivePomProfiles(modelId, currentData.getActiveProfiles());
415 result.setRawModel(modelId, currentData.getRawModel());
416 }
417
418 if (!request.isTwoPhaseBuilding()) {
419 build(request, result, importIds);
420 }
421
422 return result;
423 }
424
425 @FunctionalInterface
426 private interface InterpolateString {
427 String apply(String s) throws InterpolationException;
428 }
429
430 private List<Profile> getInterpolatedProfiles(
431 Model rawModel, DefaultProfileActivationContext context, DefaultModelProblemCollector problems) {
432 List<Profile> interpolatedActivations = getProfiles(rawModel, true);
433
434 if (interpolatedActivations.isEmpty()) {
435 return Collections.emptyList();
436 }
437 RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
438
439 interpolator.addValueSource(new MapBasedValueSource(context.getProjectProperties()));
440 interpolator.addValueSource(new MapBasedValueSource(context.getUserProperties()));
441 interpolator.addValueSource(new MapBasedValueSource(context.getSystemProperties()));
442
443 class Interpolation {
444 final InputLocationTracker target;
445
446 final InterpolateString impl;
447
448 Interpolation(InputLocationTracker target, InterpolateString impl) {
449 this.target = target;
450 this.impl = impl;
451 }
452
453 void performFor(String value, String locationKey, Consumer<String> mutator) {
454 if (StringUtils.isEmpty(value)) {
455 return;
456 }
457 try {
458 mutator.accept(impl.apply(value));
459 } catch (InterpolationException e) {
460 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
461 .setMessage("Failed to interpolate value " + value + ": " + e.getMessage())
462 .setLocation(target.getLocation(locationKey))
463 .setException(e));
464 }
465 }
466 }
467 for (Profile profile : interpolatedActivations) {
468 Activation activation = profile.getActivation();
469 Optional<Activation> a = Optional.ofNullable(activation);
470 a.map(Activation::getFile).ifPresent(fa -> {
471 Interpolation nt =
472 new Interpolation(fa, s -> profileActivationFilePathInterpolator.interpolate(s, context));
473 nt.performFor(fa.getExists(), "exists", fa::setExists);
474 nt.performFor(fa.getMissing(), "missing", fa::setMissing);
475 });
476 a.map(Activation::getOs).ifPresent(oa -> {
477 Interpolation nt = new Interpolation(oa, interpolator::interpolate);
478 nt.performFor(oa.getArch(), "arch", oa::setArch);
479 nt.performFor(oa.getFamily(), "family", oa::setFamily);
480 nt.performFor(oa.getName(), "name", oa::setName);
481 nt.performFor(oa.getVersion(), "version", oa::setVersion);
482 });
483 a.map(Activation::getProperty).ifPresent(pa -> {
484 Interpolation nt = new Interpolation(pa, interpolator::interpolate);
485 nt.performFor(pa.getName(), "name", pa::setName);
486 nt.performFor(pa.getValue(), "value", pa::setValue);
487 });
488 a.map(Activation::getJdk)
489 .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 List<Profile> getProfiles(Model model, boolean clone) {
757 ArrayList<Profile> profiles = new ArrayList<>();
758 for (Profile profile : model.getProfiles()) {
759 if (clone) {
760 profile = profile.clone();
761 }
762 profiles.add(profile);
763 }
764 return profiles;
765 }
766
767 private Model interpolateModel(Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
768
769 List<Profile> originalProfiles = getProfiles(model, true);
770
771 Model interpolatedModel =
772 modelInterpolator.interpolateModel(model, model.getProjectDirectory(), request, problems);
773 if (interpolatedModel.getParent() != null) {
774 StringSearchInterpolator ssi = new StringSearchInterpolator();
775 ssi.addValueSource(new MapBasedValueSource(request.getUserProperties()));
776
777 ssi.addValueSource(new MapBasedValueSource(model.getProperties()));
778
779 ssi.addValueSource(new MapBasedValueSource(request.getSystemProperties()));
780
781 try {
782 String interpolated =
783 ssi.interpolate(interpolatedModel.getParent().getVersion());
784 interpolatedModel.getParent().setVersion(interpolated);
785 } catch (Exception e) {
786 ModelProblemCollectorRequest mpcr = new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
787 .setMessage("Failed to interpolate field: "
788 + interpolatedModel.getParent().getVersion()
789 + " on class: ")
790 .setException(e);
791 problems.add(mpcr);
792 }
793 }
794 interpolatedModel.setPomFile(model.getPomFile());
795
796
797 List<Profile> interpolatedProfiles = model.getProfiles();
798 IntStream.range(0, interpolatedProfiles.size())
799 .forEach(i -> interpolatedProfiles
800 .get(i)
801 .setActivation(originalProfiles.get(i).getActivation()));
802
803 return interpolatedModel;
804 }
805
806 private ModelData readParent(
807 Model childModel,
808 ModelSource childSource,
809 ModelBuildingRequest request,
810 DefaultModelProblemCollector problems)
811 throws ModelBuildingException {
812 ModelData parentData;
813
814 Parent parent = childModel.getParent();
815
816 if (parent != null) {
817 String groupId = parent.getGroupId();
818 String artifactId = parent.getArtifactId();
819 String version = parent.getVersion();
820
821 parentData = getCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW);
822
823 if (parentData == null) {
824 parentData = readParentLocally(childModel, childSource, request, problems);
825
826 if (parentData == null) {
827 parentData = readParentExternally(childModel, request, problems);
828 }
829
830 putCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW, parentData);
831 } else {
832
833
834
835
836
837
838
839 File pomFile = parentData.getModel().getPomFile();
840 if (pomFile != null) {
841 FileModelSource pomSource = new FileModelSource(pomFile);
842 ModelSource expectedParentSource = getParentPomFile(childModel, childSource);
843
844 if (expectedParentSource == null
845 || (expectedParentSource instanceof ModelSource2
846 && !pomSource.equals(expectedParentSource))) {
847 parentData = readParentExternally(childModel, request, problems);
848 }
849 }
850 }
851
852 Model parentModel = parentData.getModel();
853
854 if (!"pom".equals(parentModel.getPackaging())) {
855 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
856 .setMessage("Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint(parentModel)
857 + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"")
858 .setLocation(parentModel.getLocation("packaging")));
859 }
860 } else {
861 parentData = null;
862 }
863
864 return parentData;
865 }
866
867 private ModelData readParentLocally(
868 Model childModel,
869 ModelSource childSource,
870 ModelBuildingRequest request,
871 DefaultModelProblemCollector problems)
872 throws ModelBuildingException {
873 final Parent parent = childModel.getParent();
874 final ModelSource candidateSource;
875 final Model candidateModel;
876 final WorkspaceModelResolver resolver = request.getWorkspaceModelResolver();
877 if (resolver == null) {
878 candidateSource = getParentPomFile(childModel, childSource);
879
880 if (candidateSource == null) {
881 return null;
882 }
883
884 File pomFile = null;
885 if (candidateSource instanceof FileModelSource) {
886 pomFile = ((FileModelSource) candidateSource).getPomFile();
887 }
888
889 candidateModel = readModel(candidateSource, pomFile, request, problems);
890 } else {
891 try {
892 candidateModel =
893 resolver.resolveRawModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
894 } catch (UnresolvableModelException e) {
895 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
896 .setMessage(e.getMessage().toString())
897 .setLocation(parent.getLocation(""))
898 .setException(e));
899 throw problems.newModelBuildingException();
900 }
901 if (candidateModel == null) {
902 return null;
903 }
904 candidateSource = new FileModelSource(candidateModel.getPomFile());
905 }
906
907
908
909
910
911
912
913 String groupId = candidateModel.getGroupId();
914 if (groupId == null && candidateModel.getParent() != null) {
915 groupId = candidateModel.getParent().getGroupId();
916 }
917 String artifactId = candidateModel.getArtifactId();
918 String version = candidateModel.getVersion();
919 if (version == null && candidateModel.getParent() != null) {
920 version = candidateModel.getParent().getVersion();
921 }
922
923 if (groupId == null
924 || !groupId.equals(parent.getGroupId())
925 || artifactId == null
926 || !artifactId.equals(parent.getArtifactId())) {
927 StringBuilder buffer = new StringBuilder(256);
928 buffer.append("'parent.relativePath'");
929 if (childModel != problems.getRootModel()) {
930 buffer.append(" of POM ").append(ModelProblemUtils.toSourceHint(childModel));
931 }
932 buffer.append(" points at ").append(groupId).append(':').append(artifactId);
933 buffer.append(" instead of ").append(parent.getGroupId()).append(':');
934 buffer.append(parent.getArtifactId()).append(", please verify your project structure");
935
936 problems.setSource(childModel);
937 problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.BASE)
938 .setMessage(buffer.toString())
939 .setLocation(parent.getLocation("")));
940 return null;
941 }
942 if (version != null && parent.getVersion() != null && !version.equals(parent.getVersion())) {
943 try {
944 VersionRange parentRange = VersionRange.createFromVersionSpec(parent.getVersion());
945 if (!parentRange.hasRestrictions()) {
946
947 return null;
948 }
949 if (!parentRange.containsVersion(new DefaultArtifactVersion(version))) {
950
951 return null;
952 }
953
954
955 String rawChildModelVersion = childModel.getVersion();
956
957 if (rawChildModelVersion == null) {
958
959 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
960 .setMessage("Version must be a constant")
961 .setLocation(childModel.getLocation("")));
962
963 } else {
964 if (rawChildVersionReferencesParent(rawChildModelVersion)) {
965
966 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
967 .setMessage("Version must be a constant")
968 .setLocation(childModel.getLocation("version")));
969 }
970 }
971
972
973 } catch (InvalidVersionSpecificationException e) {
974
975 return null;
976 }
977 }
978
979
980
981
982
983
984
985
986
987
988 ModelData parentData = new ModelData(candidateSource, candidateModel, groupId, artifactId, version);
989
990 return parentData;
991 }
992
993 private boolean rawChildVersionReferencesParent(String rawChildModelVersion) {
994 return rawChildModelVersion.equals("${pom.version}")
995 || rawChildModelVersion.equals("${project.version}")
996 || rawChildModelVersion.equals("${pom.parent.version}")
997 || rawChildModelVersion.equals("${project.parent.version}");
998 }
999
1000 private ModelSource getParentPomFile(Model childModel, ModelSource source) {
1001 if (!(source instanceof ModelSource2)) {
1002 return null;
1003 }
1004
1005 String parentPath = childModel.getParent().getRelativePath();
1006
1007 if (parentPath == null || parentPath.length() <= 0) {
1008 return null;
1009 }
1010
1011 return ((ModelSource2) source).getRelatedSource(parentPath);
1012 }
1013
1014 private ModelData readParentExternally(
1015 Model childModel, ModelBuildingRequest request, DefaultModelProblemCollector problems)
1016 throws ModelBuildingException {
1017 problems.setSource(childModel);
1018
1019 Parent parent = childModel.getParent().clone();
1020
1021 String groupId = parent.getGroupId();
1022 String artifactId = parent.getArtifactId();
1023 String version = parent.getVersion();
1024
1025 ModelResolver modelResolver = request.getModelResolver();
1026 Objects.requireNonNull(
1027 modelResolver,
1028 String.format(
1029 "request.modelResolver cannot be null (parent POM %s and POM %s)",
1030 ModelProblemUtils.toId(groupId, artifactId, version),
1031 ModelProblemUtils.toSourceHint(childModel)));
1032
1033 ModelSource modelSource;
1034 try {
1035 modelSource = modelResolver.resolveModel(parent);
1036 } catch (UnresolvableModelException e) {
1037
1038 StringBuilder buffer = new StringBuilder(256);
1039 buffer.append("Non-resolvable parent POM");
1040 if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
1041 buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
1042 }
1043 if (childModel != problems.getRootModel()) {
1044 buffer.append(" for ").append(ModelProblemUtils.toId(childModel));
1045 }
1046 buffer.append(": ").append(e.getMessage());
1047 if (childModel.getProjectDirectory() != null) {
1048 if (parent.getRelativePath() == null || parent.getRelativePath().length() <= 0) {
1049 buffer.append(" and 'parent.relativePath' points at no local POM");
1050 } else {
1051 buffer.append(" and 'parent.relativePath' points at wrong local POM");
1052 }
1053 }
1054
1055 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
1056 .setMessage(buffer.toString())
1057 .setLocation(parent.getLocation(""))
1058 .setException(e));
1059 throw problems.newModelBuildingException();
1060 }
1061
1062 ModelBuildingRequest lenientRequest = request;
1063 if (request.getValidationLevel() > ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
1064 lenientRequest = new FilterModelBuildingRequest(request) {
1065 @Override
1066 public int getValidationLevel() {
1067 return ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
1068 }
1069 };
1070 }
1071
1072 Model parentModel = readModel(modelSource, null, lenientRequest, problems);
1073
1074 if (!parent.getVersion().equals(version)) {
1075 String rawChildModelVersion = childModel.getVersion();
1076
1077 if (rawChildModelVersion == null) {
1078
1079 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
1080 .setMessage("Version must be a constant")
1081 .setLocation(childModel.getLocation("")));
1082
1083 } else {
1084 if (rawChildVersionReferencesParent(rawChildModelVersion)) {
1085
1086 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
1087 .setMessage("Version must be a constant")
1088 .setLocation(childModel.getLocation("version")));
1089 }
1090 }
1091
1092
1093 }
1094
1095 ModelData parentData = new ModelData(
1096 modelSource, parentModel, parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
1097
1098 return parentData;
1099 }
1100
1101 private Model getSuperModel() {
1102 return superPomProvider.getSuperModel("4.0.0").clone();
1103 }
1104
1105 @SuppressWarnings("checkstyle:methodlength")
1106 private void importDependencyManagement(
1107 Model model,
1108 ModelBuildingRequest request,
1109 DefaultModelProblemCollector problems,
1110 Collection<String> importIds) {
1111 DependencyManagement depMgmt = model.getDependencyManagement();
1112
1113 if (depMgmt == null) {
1114 return;
1115 }
1116
1117 String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion();
1118
1119 importIds.add(importing);
1120
1121 final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver();
1122 final ModelResolver modelResolver = request.getModelResolver();
1123
1124 ModelBuildingRequest importRequest = null;
1125
1126 List<DependencyManagement> importMgmts = null;
1127
1128 for (Iterator<Dependency> it = depMgmt.getDependencies().iterator(); it.hasNext(); ) {
1129 Dependency dependency = it.next();
1130
1131 if (!"pom".equals(dependency.getType()) || !"import".equals(dependency.getScope())) {
1132 continue;
1133 }
1134
1135 it.remove();
1136
1137 String groupId = dependency.getGroupId();
1138 String artifactId = dependency.getArtifactId();
1139 String version = dependency.getVersion();
1140
1141 if (groupId == null || groupId.length() <= 0) {
1142 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1143 .setMessage("'dependencyManagement.dependencies.dependency.groupId' for "
1144 + dependency.getManagementKey() + " is missing.")
1145 .setLocation(dependency.getLocation("")));
1146 continue;
1147 }
1148 if (artifactId == null || artifactId.length() <= 0) {
1149 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1150 .setMessage("'dependencyManagement.dependencies.dependency.artifactId' for "
1151 + dependency.getManagementKey() + " is missing.")
1152 .setLocation(dependency.getLocation("")));
1153 continue;
1154 }
1155 if (version == null || version.length() <= 0) {
1156 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1157 .setMessage("'dependencyManagement.dependencies.dependency.version' for "
1158 + dependency.getManagementKey() + " is missing.")
1159 .setLocation(dependency.getLocation("")));
1160 continue;
1161 }
1162
1163 String imported = groupId + ':' + artifactId + ':' + version;
1164
1165 if (importIds.contains(imported)) {
1166 String message = "The dependencies of type=pom and with scope=import form a cycle: ";
1167 for (String modelId : importIds) {
1168 message += modelId + " -> ";
1169 }
1170 message += imported;
1171 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE).setMessage(message));
1172
1173 continue;
1174 }
1175
1176 DependencyManagement importMgmt =
1177 getCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT);
1178
1179 if (importMgmt == null) {
1180 if (workspaceResolver == null && modelResolver == null) {
1181 throw new NullPointerException(String.format(
1182 "request.workspaceModelResolver and request.modelResolver cannot be null"
1183 + " (parent POM %s and POM %s)",
1184 ModelProblemUtils.toId(groupId, artifactId, version),
1185 ModelProblemUtils.toSourceHint(model)));
1186 }
1187
1188 Model importModel = null;
1189 if (workspaceResolver != null) {
1190 try {
1191 importModel = workspaceResolver.resolveEffectiveModel(groupId, artifactId, version);
1192 } catch (UnresolvableModelException e) {
1193 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
1194 .setMessage(e.getMessage().toString())
1195 .setException(e));
1196 continue;
1197 }
1198 }
1199
1200
1201 if (importModel == null) {
1202 final ModelSource importSource;
1203 try {
1204 importSource = modelResolver.resolveModel(groupId, artifactId, version);
1205 } catch (UnresolvableModelException e) {
1206 StringBuilder buffer = new StringBuilder(256);
1207 buffer.append("Non-resolvable import POM");
1208 if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
1209 buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
1210 }
1211 buffer.append(": ").append(e.getMessage());
1212
1213 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1214 .setMessage(buffer.toString())
1215 .setLocation(dependency.getLocation(""))
1216 .setException(e));
1217 continue;
1218 }
1219
1220 if (importRequest == null) {
1221 importRequest = new DefaultModelBuildingRequest();
1222 importRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
1223 importRequest.setModelCache(request.getModelCache());
1224 importRequest.setSystemProperties(request.getSystemProperties());
1225 importRequest.setUserProperties(request.getUserProperties());
1226 importRequest.setLocationTracking(request.isLocationTracking());
1227 }
1228
1229 importRequest.setModelSource(importSource);
1230 importRequest.setModelResolver(modelResolver.newCopy());
1231
1232 final ModelBuildingResult importResult;
1233 try {
1234 importResult = build(importRequest, importIds);
1235 } catch (ModelBuildingException e) {
1236 problems.addAll(e.getProblems());
1237 continue;
1238 }
1239
1240 problems.addAll(importResult.getProblems());
1241
1242 importModel = importResult.getEffectiveModel();
1243 }
1244
1245 importMgmt = importModel.getDependencyManagement();
1246
1247 if (importMgmt == null) {
1248 importMgmt = new DependencyManagement();
1249 }
1250
1251 putCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt);
1252 }
1253
1254 if (importMgmts == null) {
1255 importMgmts = new ArrayList<>();
1256 }
1257
1258 importMgmts.add(importMgmt);
1259 }
1260
1261 importIds.remove(importing);
1262
1263 dependencyManagementImporter.importManagement(model, importMgmts, request, problems);
1264 }
1265
1266 private <T> void putCache(
1267 ModelCache modelCache, String groupId, String artifactId, String version, ModelCacheTag<T> tag, T data) {
1268 if (modelCache != null) {
1269 modelCache.put(groupId, artifactId, version, tag.getName(), tag.intoCache(data));
1270 }
1271 }
1272
1273 private <T> T getCache(
1274 ModelCache modelCache, String groupId, String artifactId, String version, ModelCacheTag<T> tag) {
1275 if (modelCache != null) {
1276 Object data = modelCache.get(groupId, artifactId, version, tag.getName());
1277 if (data != null) {
1278 return tag.fromCache(tag.getType().cast(data));
1279 }
1280 }
1281 return null;
1282 }
1283
1284 private void fireEvent(
1285 Model model,
1286 ModelBuildingRequest request,
1287 ModelProblemCollector problems,
1288 ModelBuildingEventCatapult catapult)
1289 throws ModelBuildingException {
1290 ModelBuildingListener listener = request.getModelBuildingListener();
1291
1292 if (listener != null) {
1293 ModelBuildingEvent event = new DefaultModelBuildingEvent(model, request, problems);
1294
1295 catapult.fire(listener, event);
1296 }
1297 }
1298
1299 private boolean containsCoordinates(String message, String groupId, String artifactId, String version) {
1300 return message != null
1301 && (groupId == null || message.contains(groupId))
1302 && (artifactId == null || message.contains(artifactId))
1303 && (version == null || message.contains(version));
1304 }
1305
1306 protected boolean hasModelErrors(ModelProblemCollectorExt problems) {
1307 if (problems instanceof DefaultModelProblemCollector) {
1308 return ((DefaultModelProblemCollector) problems).hasErrors();
1309 } else {
1310
1311
1312 throw new IllegalStateException();
1313 }
1314 }
1315
1316 protected boolean hasFatalErrors(ModelProblemCollectorExt problems) {
1317 if (problems instanceof DefaultModelProblemCollector) {
1318 return ((DefaultModelProblemCollector) problems).hasFatalErrors();
1319 } else {
1320
1321
1322 throw new IllegalStateException();
1323 }
1324 }
1325 }