View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
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   * @deprecated use {@code org.apache.maven.api.services.ModelBuilder} instead
95   */
96  @SuppressWarnings("UnusedReturnValue")
97  @Named
98  @Singleton
99  @Deprecated(since = "4.0.0")
100 public class DefaultModelBuilder implements ModelBuilder {
101     @Inject
102     private ModelProcessor modelProcessor;
103 
104     @Inject
105     private ModelValidator modelValidator;
106 
107     @Inject
108     private ModelNormalizer modelNormalizer;
109 
110     @Inject
111     private ModelInterpolator modelInterpolator;
112 
113     @Inject
114     private ModelPathTranslator modelPathTranslator;
115 
116     @Inject
117     private ModelUrlNormalizer modelUrlNormalizer;
118 
119     @Inject
120     private SuperPomProvider superPomProvider;
121 
122     @Inject
123     private InheritanceAssembler inheritanceAssembler;
124 
125     @Inject
126     private ProfileSelector profileSelector;
127 
128     @Inject
129     private ProfileInjector profileInjector;
130 
131     @Inject
132     private PluginManagementInjector pluginManagementInjector;
133 
134     @Inject
135     private DependencyManagementInjector dependencyManagementInjector;
136 
137     @Inject
138     private DependencyManagementImporter dependencyManagementImporter;
139 
140     @Inject
141     @Nullable
142     private LifecycleBindingsInjector lifecycleBindingsInjector;
143 
144     @Inject
145     private PluginConfigurationExpander pluginConfigurationExpander;
146 
147     @Inject
148     private ReportConfigurationExpander reportConfigurationExpander;
149 
150     @Inject
151     private ReportingConverter reportingConverter;
152 
153     @Inject
154     private ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator;
155 
156     public DefaultModelBuilder setModelProcessor(ModelProcessor modelProcessor) {
157         this.modelProcessor = modelProcessor;
158         return this;
159     }
160 
161     public DefaultModelBuilder setModelValidator(ModelValidator modelValidator) {
162         this.modelValidator = modelValidator;
163         return this;
164     }
165 
166     public DefaultModelBuilder setModelNormalizer(ModelNormalizer modelNormalizer) {
167         this.modelNormalizer = modelNormalizer;
168         return this;
169     }
170 
171     public DefaultModelBuilder setModelInterpolator(ModelInterpolator modelInterpolator) {
172         this.modelInterpolator = modelInterpolator;
173         return this;
174     }
175 
176     public DefaultModelBuilder setModelPathTranslator(ModelPathTranslator modelPathTranslator) {
177         this.modelPathTranslator = modelPathTranslator;
178         return this;
179     }
180 
181     public DefaultModelBuilder setModelUrlNormalizer(ModelUrlNormalizer modelUrlNormalizer) {
182         this.modelUrlNormalizer = modelUrlNormalizer;
183         return this;
184     }
185 
186     public DefaultModelBuilder setSuperPomProvider(SuperPomProvider superPomProvider) {
187         this.superPomProvider = superPomProvider;
188         return this;
189     }
190 
191     public DefaultModelBuilder setProfileSelector(ProfileSelector profileSelector) {
192         this.profileSelector = profileSelector;
193         return this;
194     }
195 
196     public DefaultModelBuilder setProfileInjector(ProfileInjector profileInjector) {
197         this.profileInjector = profileInjector;
198         return this;
199     }
200 
201     public DefaultModelBuilder setInheritanceAssembler(InheritanceAssembler inheritanceAssembler) {
202         this.inheritanceAssembler = inheritanceAssembler;
203         return this;
204     }
205 
206     public DefaultModelBuilder setDependencyManagementImporter(DependencyManagementImporter depMgmtImporter) {
207         this.dependencyManagementImporter = depMgmtImporter;
208         return this;
209     }
210 
211     public DefaultModelBuilder setDependencyManagementInjector(DependencyManagementInjector depMgmtInjector) {
212         this.dependencyManagementInjector = depMgmtInjector;
213         return this;
214     }
215 
216     public DefaultModelBuilder setLifecycleBindingsInjector(LifecycleBindingsInjector lifecycleBindingsInjector) {
217         this.lifecycleBindingsInjector = lifecycleBindingsInjector;
218         return this;
219     }
220 
221     public DefaultModelBuilder setPluginConfigurationExpander(PluginConfigurationExpander pluginConfigurationExpander) {
222         this.pluginConfigurationExpander = pluginConfigurationExpander;
223         return this;
224     }
225 
226     public DefaultModelBuilder setPluginManagementInjector(PluginManagementInjector pluginManagementInjector) {
227         this.pluginManagementInjector = pluginManagementInjector;
228         return this;
229     }
230 
231     public DefaultModelBuilder setReportConfigurationExpander(ReportConfigurationExpander reportConfigurationExpander) {
232         this.reportConfigurationExpander = reportConfigurationExpander;
233         return this;
234     }
235 
236     public DefaultModelBuilder setReportingConverter(ReportingConverter reportingConverter) {
237         this.reportingConverter = reportingConverter;
238         return this;
239     }
240 
241     public DefaultModelBuilder setProfileActivationFilePathInterpolator(
242             ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator) {
243         this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator;
244         return this;
245     }
246 
247     @SuppressWarnings("checkstyle:methodlength")
248     @Override
249     public ModelBuildingResult build(ModelBuildingRequest request) throws ModelBuildingException {
250         return build(request, new LinkedHashSet<String>());
251     }
252 
253     @SuppressWarnings("checkstyle:methodlength")
254     protected ModelBuildingResult build(ModelBuildingRequest request, Collection<String> importIds)
255             throws ModelBuildingException {
256         // phase 1
257         DefaultModelBuildingResult result = new DefaultModelBuildingResult();
258 
259         DefaultModelProblemCollector problems = new DefaultModelProblemCollector(result);
260 
261         // read and validate raw model
262         Model inputModel = request.getRawModel();
263         if (inputModel == null) {
264             inputModel = readModel(request.getModelSource(), request.getPomFile(), request, problems);
265         }
266 
267         // profile activation
268         DefaultProfileActivationContext profileActivationContext = getProfileActivationContext(request, inputModel);
269 
270         problems.setSource("(external profiles)");
271         List<Profile> activeExternalProfiles =
272                 profileSelector.getActiveProfiles(request.getProfiles(), profileActivationContext, problems);
273 
274         result.setActiveExternalProfiles(activeExternalProfiles);
275 
276         if (!activeExternalProfiles.isEmpty()) {
277             Properties profileProps = new Properties();
278             for (Profile profile : activeExternalProfiles) {
279                 profileProps.putAll(profile.getProperties());
280             }
281             profileProps.putAll(profileActivationContext.getUserProperties());
282             profileActivationContext.setUserProperties(profileProps);
283         }
284 
285         problems.setRootModel(inputModel);
286 
287         ModelData resultData = new ModelData(request.getModelSource(), inputModel);
288         ModelData superData = new ModelData(null, getSuperModel());
289 
290         Collection<String> parentIds = new LinkedHashSet<>();
291         List<ModelData> lineage = new ArrayList<>();
292 
293         for (ModelData currentData = resultData; currentData != null; ) {
294             lineage.add(currentData);
295 
296             Model rawModel = currentData.getModel();
297             currentData.setRawModel(rawModel);
298 
299             Model tmpModel = rawModel.clone();
300             currentData.setModel(tmpModel);
301 
302             problems.setSource(tmpModel);
303 
304             // model normalization
305             modelNormalizer.mergeDuplicates(tmpModel, request, problems);
306 
307             profileActivationContext.setProjectProperties(tmpModel.getProperties());
308 
309             List<Profile> interpolatedProfiles = getInterpolatedProfiles(rawModel, profileActivationContext, problems);
310             tmpModel.setProfiles(interpolatedProfiles);
311 
312             List<Profile> activePomProfiles =
313                     profileSelector.getActiveProfiles(tmpModel.getProfiles(), profileActivationContext, problems);
314 
315             List<Profile> rawProfiles = new ArrayList<>();
316             for (Profile activePomProfile : activePomProfiles) {
317                 rawProfiles.add(rawModel.getProfiles().get(interpolatedProfiles.indexOf(activePomProfile)));
318             }
319             currentData.setActiveProfiles(rawProfiles);
320 
321             // profile injection
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) { // First iteration - add initial id after version resolution.
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                 // Reset - only needed for 'getId'.
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         // inheritance assembly
380         assembleInheritance(lineage, request, problems);
381 
382         Model resultModel = resultData.getModel();
383 
384         problems.setSource(resultModel);
385         problems.setRootModel(resultModel);
386 
387         // model interpolation
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                 // parentData.setModel( interpolatedParent );
396                 parentData.setVersion(interpolatedParent.getVersion());
397             }
398         }
399 
400         // url normalization
401         modelUrlNormalizer.normalize(resultModel, request);
402 
403         // Now the fully interpolated model is available: reconfigure the resolver
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 List<Profile> getInterpolatedProfiles(
433             Model rawModel, DefaultProfileActivationContext context, DefaultModelProblemCollector problems) {
434         List<Profile> interpolatedActivations = getProfiles(rawModel, true);
435 
436         if (interpolatedActivations.isEmpty()) {
437             return Collections.emptyList();
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 (Profile profile : interpolatedActivations) {
470             Activation activation = profile.getActivation();
471             Optional<Activation> a = Optional.ofNullable(activation);
472             a.map(Activation::getFile).ifPresent(fa -> {
473                 Interpolation nt =
474                         new Interpolation(fa, s -> profileActivationFilePathInterpolator.interpolate(s, context));
475                 nt.performFor(fa.getExists(), "exists", fa::setExists);
476                 nt.performFor(fa.getMissing(), "missing", fa::setMissing);
477             });
478             a.map(Activation::getOs).ifPresent(oa -> {
479                 Interpolation nt = new Interpolation(oa, interpolator::interpolate);
480                 nt.performFor(oa.getArch(), "arch", oa::setArch);
481                 nt.performFor(oa.getFamily(), "family", oa::setFamily);
482                 nt.performFor(oa.getName(), "name", oa::setName);
483                 nt.performFor(oa.getVersion(), "version", oa::setVersion);
484             });
485             a.map(Activation::getProperty).ifPresent(pa -> {
486                 Interpolation nt = new Interpolation(pa, interpolator::interpolate);
487                 nt.performFor(pa.getName(), "name", pa::setName);
488                 nt.performFor(pa.getValue(), "value", pa::setValue);
489             });
490             a.map(Activation::getJdk).ifPresent(ja -> new Interpolation(activation, interpolator::interpolate)
491                     .performFor(ja, "jdk", activation::setJdk));
492         }
493         return interpolatedActivations;
494     }
495 
496     @Override
497     public ModelBuildingResult build(ModelBuildingRequest request, ModelBuildingResult result)
498             throws ModelBuildingException {
499         return build(request, result, new LinkedHashSet<String>());
500     }
501 
502     private ModelBuildingResult build(
503             ModelBuildingRequest request, ModelBuildingResult result, Collection<String> imports)
504             throws ModelBuildingException {
505         // phase 2
506         Model resultModel = result.getEffectiveModel();
507 
508         DefaultModelProblemCollector problems = new DefaultModelProblemCollector(result);
509         problems.setSource(resultModel);
510         problems.setRootModel(resultModel);
511 
512         // model path translation
513         modelPathTranslator.alignToBaseDirectory(resultModel, resultModel.getProjectDirectory(), request);
514 
515         // plugin management injection
516         pluginManagementInjector.injectManagement(resultModel, request, problems);
517 
518         fireEvent(resultModel, request, problems, ModelBuildingEventCatapult.BUILD_EXTENSIONS_ASSEMBLED);
519 
520         if (request.isProcessPlugins()) {
521             if (lifecycleBindingsInjector == null) {
522                 throw new IllegalStateException("lifecycle bindings injector is missing");
523             }
524 
525             // lifecycle bindings injection
526             lifecycleBindingsInjector.injectLifecycleBindings(resultModel, request, problems);
527         }
528 
529         // dependency management import
530         importDependencyManagement(resultModel, request, problems, imports);
531 
532         // dependency management injection
533         dependencyManagementInjector.injectManagement(resultModel, request, problems);
534 
535         modelNormalizer.injectDefaultValues(resultModel, request, problems);
536 
537         if (request.isProcessPlugins()) {
538             // reports configuration
539             reportConfigurationExpander.expandPluginConfiguration(resultModel, request, problems);
540 
541             // reports conversion to decoupled site plugin
542             reportingConverter.convertReporting(resultModel, request, problems);
543 
544             // plugins configuration
545             pluginConfigurationExpander.expandPluginConfiguration(resultModel, request, problems);
546         }
547 
548         // effective model validation
549         modelValidator.validateEffectiveModel(resultModel, request, problems);
550 
551         if (hasModelErrors(problems)) {
552             throw problems.newModelBuildingException();
553         }
554 
555         return result;
556     }
557 
558     @Override
559     public Result<? extends Model> buildRawModel(File pomFile, int validationLevel, boolean locationTracking) {
560         final ModelBuildingRequest request = new DefaultModelBuildingRequest()
561                 .setValidationLevel(validationLevel)
562                 .setLocationTracking(locationTracking);
563         final DefaultModelProblemCollector collector =
564                 new DefaultModelProblemCollector(new DefaultModelBuildingResult());
565         try {
566             return newResult(readModel(null, pomFile, request, collector), collector.getProblems());
567         } catch (ModelBuildingException e) {
568             return error(collector.getProblems());
569         }
570     }
571 
572     private Model readModel(
573             ModelSource modelSource, File pomFile, ModelBuildingRequest request, DefaultModelProblemCollector problems)
574             throws ModelBuildingException {
575         Model model;
576 
577         if (modelSource == null) {
578             if (pomFile != null) {
579                 modelSource = new FileModelSource(pomFile);
580             } else {
581                 throw new NullPointerException("neither pomFile nor modelSource can be null");
582             }
583         }
584 
585         problems.setSource(modelSource.getLocation());
586         try {
587             boolean strict = request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
588             InputSource source = request.isLocationTracking() ? new InputSource() : null;
589 
590             Map<String, Object> options = new HashMap<>();
591             options.put(ModelProcessor.IS_STRICT, strict);
592             options.put(ModelProcessor.INPUT_SOURCE, source);
593             options.put(ModelProcessor.SOURCE, modelSource);
594 
595             try {
596                 model = modelProcessor.read(modelSource.getInputStream(), options);
597             } catch (ModelParseException e) {
598                 if (!strict) {
599                     throw e;
600                 }
601 
602                 options.put(ModelProcessor.IS_STRICT, Boolean.FALSE);
603 
604                 try {
605                     model = modelProcessor.read(modelSource.getInputStream(), options);
606                 } catch (ModelParseException ne) {
607                     // still unreadable even in non-strict mode, rethrow original error
608                     throw e;
609                 }
610 
611                 if (pomFile != null) {
612                     problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.V20)
613                             .setMessage("Malformed POM " + modelSource.getLocation() + ": " + e.getMessage())
614                             .setException(e));
615                 } else {
616                     problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.V20)
617                             .setMessage("Malformed POM " + modelSource.getLocation() + ": " + e.getMessage())
618                             .setException(e));
619                 }
620             }
621 
622             if (source != null) {
623                 source.setModelId(ModelProblemUtils.toId(model));
624                 source.setLocation(modelSource.getLocation());
625             }
626         } catch (ModelParseException e) {
627             problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
628                     .setMessage("Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage())
629                     .setException(e));
630             throw problems.newModelBuildingException();
631         } catch (IOException e) {
632             String msg = e.getMessage();
633             if (msg == null || msg.length() <= 0) {
634                 // NOTE: There's java.nio.charset.MalformedInputException and sun.io.MalformedInputException
635                 if (e.getClass().getName().endsWith("MalformedInputException")) {
636                     msg = "Some input bytes do not match the file encoding.";
637                 } else {
638                     msg = e.getClass().getSimpleName();
639                 }
640             }
641             problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
642                     .setMessage("Non-readable POM " + modelSource.getLocation() + ": " + msg)
643                     .setException(e));
644             throw problems.newModelBuildingException();
645         }
646 
647         model.setPomFile(pomFile);
648 
649         problems.setSource(model);
650         modelValidator.validateRawModel(model, request, problems);
651 
652         if (hasFatalErrors(problems)) {
653             throw problems.newModelBuildingException();
654         }
655 
656         return model;
657     }
658 
659     private DefaultProfileActivationContext getProfileActivationContext(ModelBuildingRequest request, Model rawModel) {
660         DefaultProfileActivationContext context = new DefaultProfileActivationContext();
661 
662         context.setActiveProfileIds(request.getActiveProfileIds());
663         context.setInactiveProfileIds(request.getInactiveProfileIds());
664         context.setSystemProperties(request.getSystemProperties());
665         // enrich user properties with project packaging
666         Properties userProperties = request.getUserProperties();
667         userProperties.computeIfAbsent(
668                 (Object) ProfileActivationContext.PROPERTY_NAME_PACKAGING, (p) -> (Object) rawModel.getPackaging());
669         context.setUserProperties(userProperties);
670         context.setProjectDirectory(
671                 (request.getPomFile() != null) ? request.getPomFile().getParentFile() : null);
672 
673         return context;
674     }
675 
676     private void configureResolver(ModelResolver modelResolver, Model model, DefaultModelProblemCollector problems) {
677         configureResolver(modelResolver, model, problems, false);
678     }
679 
680     private void configureResolver(
681             ModelResolver modelResolver,
682             Model model,
683             DefaultModelProblemCollector problems,
684             boolean replaceRepositories) {
685         if (modelResolver == null) {
686             return;
687         }
688 
689         problems.setSource(model);
690 
691         List<Repository> repositories = model.getRepositories();
692 
693         for (Repository repository : repositories) {
694             try {
695                 modelResolver.addRepository(repository, replaceRepositories);
696             } catch (InvalidRepositoryException e) {
697                 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
698                         .setMessage("Invalid repository " + repository.getId() + ": " + e.getMessage())
699                         .setLocation(repository.getLocation(""))
700                         .setException(e));
701             }
702         }
703     }
704 
705     private void checkPluginVersions(
706             List<ModelData> lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
707         if (request.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
708             return;
709         }
710 
711         Map<String, Plugin> plugins = new HashMap<>();
712         Map<String, String> versions = new HashMap<>();
713         Map<String, String> managedVersions = new HashMap<>();
714 
715         for (int i = lineage.size() - 1; i >= 0; i--) {
716             Model model = lineage.get(i).getModel();
717             Build build = model.getBuild();
718             if (build != null) {
719                 for (Plugin plugin : build.getPlugins()) {
720                     String key = plugin.getKey();
721                     if (versions.get(key) == null) {
722                         versions.put(key, plugin.getVersion());
723                         plugins.put(key, plugin);
724                     }
725                 }
726                 PluginManagement mgmt = build.getPluginManagement();
727                 if (mgmt != null) {
728                     for (Plugin plugin : mgmt.getPlugins()) {
729                         String key = plugin.getKey();
730                         if (managedVersions.get(key) == null) {
731                             managedVersions.put(key, plugin.getVersion());
732                         }
733                     }
734                 }
735             }
736         }
737 
738         for (String key : versions.keySet()) {
739             if (versions.get(key) == null && managedVersions.get(key) == null) {
740                 InputLocation location = plugins.get(key).getLocation("");
741                 problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.V20)
742                         .setMessage("'build.plugins.plugin.version' for " + key + " is missing.")
743                         .setLocation(location));
744             }
745         }
746     }
747 
748     private void assembleInheritance(
749             List<ModelData> lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
750         for (int i = lineage.size() - 2; i >= 0; i--) {
751             Model parent = lineage.get(i + 1).getModel();
752             Model child = lineage.get(i).getModel();
753             inheritanceAssembler.assembleModelInheritance(child, parent, request, problems);
754         }
755     }
756 
757     private List<Profile> getProfiles(Model model, boolean clone) {
758         ArrayList<Profile> profiles = new ArrayList<>();
759         for (Profile profile : model.getProfiles()) {
760             if (clone) {
761                 profile = profile.clone();
762             }
763             profiles.add(profile);
764         }
765         return profiles;
766     }
767 
768     private Model interpolateModel(Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
769         // save profile activations before interpolation, since they are evaluated with limited scope
770         List<Profile> originalProfiles = getProfiles(model, true);
771 
772         Model interpolatedModel =
773                 modelInterpolator.interpolateModel(model, model.getProjectDirectory(), request, problems);
774         if (interpolatedModel.getParent() != null) {
775             StringSearchInterpolator ssi = new StringSearchInterpolator();
776             ssi.addValueSource(new MapBasedValueSource(request.getUserProperties()));
777 
778             ssi.addValueSource(new MapBasedValueSource(model.getProperties()));
779 
780             ssi.addValueSource(new MapBasedValueSource(request.getSystemProperties()));
781 
782             try {
783                 String interpolated =
784                         ssi.interpolate(interpolatedModel.getParent().getVersion());
785                 interpolatedModel.getParent().setVersion(interpolated);
786             } catch (Exception e) {
787                 ModelProblemCollectorRequest mpcr = new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
788                         .setMessage("Failed to interpolate field: "
789                                 + interpolatedModel.getParent().getVersion()
790                                 + " on class: ")
791                         .setException(e);
792                 problems.add(mpcr);
793             }
794         }
795         interpolatedModel.setPomFile(model.getPomFile());
796 
797         // restore profiles with any activation to their value before full interpolation
798         List<Profile> interpolatedProfiles = model.getProfiles();
799         IntStream.range(0, interpolatedProfiles.size()).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                  * NOTE: This is a sanity check of the cache hit. If the cached parent POM was locally resolved, the
834                  * child's <relativePath> should point at that parent, too. If it doesn't, we ignore the cache and
835                  * resolve externally, to mimic the behavior if the cache didn't exist in the first place. Otherwise,
836                  * the cache would obscure a bad POM.
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 source) {
886                 pomFile = source.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         // TODO jvz Why isn't all this checking the job of the duty of the workspace resolver, we know that we
909         // have a model that is suitable, yet more checks are done here and the one for the version is problematic
910         // before because with parents as ranges it will never work in this scenario.
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                     // the parent version is not a range, we have version skew, drop back to resolution from repo
947                     return null;
948                 }
949                 if (!parentRange.containsVersion(new DefaultArtifactVersion(version))) {
950                     // version skew drop back to resolution from the repository
951                     return null;
952                 }
953 
954                 // Validate versions aren't inherited when using parent ranges the same way as when read externally.
955                 String rawChildModelVersion = childModel.getVersion();
956 
957                 if (rawChildModelVersion == null) {
958                     // Message below is checked for in the MNG-2199 core IT.
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                         // Message below is checked for in the MNG-2199 core IT.
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                 // MNG-2199: What else to check here ?
973             } catch (InvalidVersionSpecificationException e) {
974                 // invalid version range, so drop back to resolution from the repository
975                 return null;
976             }
977         }
978 
979         //
980         // Here we just need to know that a version is fine to use but this validation we can do in our workspace
981         // resolver.
982         //
983 
984         /*
985          * if ( version == null || !version.equals( parent.getVersion() ) ) { return null; }
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         if (parentPath == null) {
1007             parentPath = "../pom.xml";
1008         }
1009 
1010         if (parentPath.length() <= 0) {
1011             return null;
1012         }
1013 
1014         return ((ModelSource2) source).getRelatedSource(parentPath);
1015     }
1016 
1017     private ModelData readParentExternally(
1018             Model childModel, ModelBuildingRequest request, DefaultModelProblemCollector problems)
1019             throws ModelBuildingException {
1020         problems.setSource(childModel);
1021 
1022         Parent parent = childModel.getParent().clone();
1023 
1024         String groupId = parent.getGroupId();
1025         String artifactId = parent.getArtifactId();
1026         String version = parent.getVersion();
1027 
1028         ModelResolver modelResolver = request.getModelResolver();
1029         Objects.requireNonNull(
1030                 modelResolver,
1031                 String.format(
1032                         "request.modelResolver cannot be null (parent POM %s and POM %s)",
1033                         ModelProblemUtils.toId(groupId, artifactId, version),
1034                         ModelProblemUtils.toSourceHint(childModel)));
1035 
1036         ModelSource modelSource;
1037         try {
1038             modelSource = modelResolver.resolveModel(parent);
1039         } catch (UnresolvableModelException e) {
1040             // Message below is checked for in the MNG-2199 core IT.
1041             StringBuilder buffer = new StringBuilder(256);
1042             buffer.append("Non-resolvable parent POM");
1043             if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
1044                 buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
1045             }
1046             if (childModel != problems.getRootModel()) {
1047                 buffer.append(" for ").append(ModelProblemUtils.toId(childModel));
1048             }
1049             buffer.append(": ").append(e.getMessage());
1050             if (childModel.getProjectDirectory() != null) {
1051                 if (parent.getRelativePath() == null || parent.getRelativePath().length() <= 0) {
1052                     buffer.append(" and 'parent.relativePath' points at no local POM");
1053                 } else {
1054                     buffer.append(" and 'parent.relativePath' points at wrong local POM");
1055                 }
1056             }
1057 
1058             problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
1059                     .setMessage(buffer.toString())
1060                     .setLocation(parent.getLocation(""))
1061                     .setException(e));
1062             throw problems.newModelBuildingException();
1063         }
1064 
1065         ModelBuildingRequest lenientRequest = request;
1066         if (request.getValidationLevel() > ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
1067             lenientRequest = new FilterModelBuildingRequest(request) {
1068                 @Override
1069                 public int getValidationLevel() {
1070                     return ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
1071                 }
1072             };
1073         }
1074 
1075         Model parentModel = readModel(modelSource, null, lenientRequest, problems);
1076 
1077         if (!parent.getVersion().equals(version)) {
1078             String rawChildModelVersion = childModel.getVersion();
1079 
1080             if (rawChildModelVersion == null) {
1081                 // Message below is checked for in the MNG-2199 core IT.
1082                 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
1083                         .setMessage("Version must be a constant")
1084                         .setLocation(childModel.getLocation("")));
1085 
1086             } else {
1087                 if (rawChildVersionReferencesParent(rawChildModelVersion)) {
1088                     // Message below is checked for in the MNG-2199 core IT.
1089                     problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
1090                             .setMessage("Version must be a constant")
1091                             .setLocation(childModel.getLocation("version")));
1092                 }
1093             }
1094 
1095             // MNG-2199: What else to check here ?
1096         }
1097 
1098         ModelData parentData = new ModelData(
1099                 modelSource, parentModel, parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
1100 
1101         return parentData;
1102     }
1103 
1104     private Model getSuperModel() {
1105         return superPomProvider.getSuperModel("4.0.0").clone();
1106     }
1107 
1108     @SuppressWarnings("checkstyle:methodlength")
1109     private void importDependencyManagement(
1110             Model model,
1111             ModelBuildingRequest request,
1112             DefaultModelProblemCollector problems,
1113             Collection<String> importIds) {
1114         DependencyManagement depMgmt = model.getDependencyManagement();
1115 
1116         if (depMgmt == null) {
1117             return;
1118         }
1119 
1120         String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion();
1121 
1122         importIds.add(importing);
1123 
1124         final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver();
1125         final ModelResolver modelResolver = request.getModelResolver();
1126 
1127         ModelBuildingRequest importRequest = null;
1128 
1129         List<DependencyManagement> importMgmts = null;
1130 
1131         for (Iterator<Dependency> it = depMgmt.getDependencies().iterator(); it.hasNext(); ) {
1132             Dependency dependency = it.next();
1133 
1134             if (!"pom".equals(dependency.getType()) || !"import".equals(dependency.getScope())) {
1135                 continue;
1136             }
1137 
1138             it.remove();
1139 
1140             String groupId = dependency.getGroupId();
1141             String artifactId = dependency.getArtifactId();
1142             String version = dependency.getVersion();
1143 
1144             if (groupId == null || groupId.length() <= 0) {
1145                 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1146                         .setMessage("'dependencyManagement.dependencies.dependency.groupId' for "
1147                                 + dependency.getManagementKey() + " is missing.")
1148                         .setLocation(dependency.getLocation("")));
1149                 continue;
1150             }
1151             if (artifactId == null || artifactId.length() <= 0) {
1152                 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1153                         .setMessage("'dependencyManagement.dependencies.dependency.artifactId' for "
1154                                 + dependency.getManagementKey() + " is missing.")
1155                         .setLocation(dependency.getLocation("")));
1156                 continue;
1157             }
1158             if (version == null || version.length() <= 0) {
1159                 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1160                         .setMessage("'dependencyManagement.dependencies.dependency.version' for "
1161                                 + dependency.getManagementKey() + " is missing.")
1162                         .setLocation(dependency.getLocation("")));
1163                 continue;
1164             }
1165 
1166             String imported = groupId + ':' + artifactId + ':' + version;
1167 
1168             if (importIds.contains(imported)) {
1169                 String message = "The dependencies of type=pom and with scope=import form a cycle: ";
1170                 for (String modelId : importIds) {
1171                     message += modelId + " -> ";
1172                 }
1173                 message += imported;
1174                 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE).setMessage(message));
1175 
1176                 continue;
1177             }
1178 
1179             DependencyManagement importMgmt =
1180                     getCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT);
1181 
1182             if (importMgmt == null) {
1183                 if (workspaceResolver == null && modelResolver == null) {
1184                     throw new NullPointerException(String.format(
1185                             "request.workspaceModelResolver and request.modelResolver cannot be null"
1186                                     + " (parent POM %s and POM %s)",
1187                             ModelProblemUtils.toId(groupId, artifactId, version),
1188                             ModelProblemUtils.toSourceHint(model)));
1189                 }
1190 
1191                 Model importModel = null;
1192                 if (workspaceResolver != null) {
1193                     try {
1194                         importModel = workspaceResolver.resolveEffectiveModel(groupId, artifactId, version);
1195                     } catch (UnresolvableModelException e) {
1196                         problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
1197                                 .setMessage(e.getMessage().toString())
1198                                 .setException(e));
1199                         continue;
1200                     }
1201                 }
1202 
1203                 // no workspace resolver or workspace resolver returned null (i.e. model not in workspace)
1204                 if (importModel == null) {
1205                     final ModelSource importSource;
1206                     try {
1207                         importSource = modelResolver.resolveModel(groupId, artifactId, version);
1208                     } catch (UnresolvableModelException e) {
1209                         StringBuilder buffer = new StringBuilder(256);
1210                         buffer.append("Non-resolvable import POM");
1211                         if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
1212                             buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
1213                         }
1214                         buffer.append(": ").append(e.getMessage());
1215 
1216                         problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1217                                 .setMessage(buffer.toString())
1218                                 .setLocation(dependency.getLocation(""))
1219                                 .setException(e));
1220                         continue;
1221                     }
1222 
1223                     if (importRequest == null) {
1224                         importRequest = new DefaultModelBuildingRequest();
1225                         importRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
1226                         importRequest.setModelCache(request.getModelCache());
1227                         importRequest.setSystemProperties(request.getSystemProperties());
1228                         importRequest.setUserProperties(request.getUserProperties());
1229                         importRequest.setLocationTracking(request.isLocationTracking());
1230                     }
1231 
1232                     importRequest.setModelSource(importSource);
1233                     importRequest.setModelResolver(modelResolver.newCopy());
1234 
1235                     final ModelBuildingResult importResult;
1236                     try {
1237                         importResult = build(importRequest, importIds);
1238                     } catch (ModelBuildingException e) {
1239                         problems.addAll(e.getProblems());
1240                         continue;
1241                     }
1242 
1243                     problems.addAll(importResult.getProblems());
1244 
1245                     importModel = importResult.getEffectiveModel();
1246                 }
1247 
1248                 importMgmt = importModel.getDependencyManagement();
1249 
1250                 if (importMgmt == null) {
1251                     importMgmt = new DependencyManagement();
1252                 }
1253 
1254                 putCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt);
1255             }
1256 
1257             if (importMgmts == null) {
1258                 importMgmts = new ArrayList<>();
1259             }
1260 
1261             importMgmts.add(importMgmt);
1262         }
1263 
1264         importIds.remove(importing);
1265 
1266         dependencyManagementImporter.importManagement(model, importMgmts, request, problems);
1267     }
1268 
1269     private <T> void putCache(
1270             ModelCache modelCache, String groupId, String artifactId, String version, ModelCacheTag<T> tag, T data) {
1271         if (modelCache != null) {
1272             modelCache.put(groupId, artifactId, version, tag.getName(), tag.intoCache(data));
1273         }
1274     }
1275 
1276     private <T> T getCache(
1277             ModelCache modelCache, String groupId, String artifactId, String version, ModelCacheTag<T> tag) {
1278         if (modelCache != null) {
1279             Object data = modelCache.get(groupId, artifactId, version, tag.getName());
1280             if (data != null) {
1281                 return tag.fromCache(tag.getType().cast(data));
1282             }
1283         }
1284         return null;
1285     }
1286 
1287     private void fireEvent(
1288             Model model,
1289             ModelBuildingRequest request,
1290             ModelProblemCollector problems,
1291             ModelBuildingEventCatapult catapult)
1292             throws ModelBuildingException {
1293         ModelBuildingListener listener = request.getModelBuildingListener();
1294 
1295         if (listener != null) {
1296             ModelBuildingEvent event = new DefaultModelBuildingEvent(model, request, problems);
1297 
1298             catapult.fire(listener, event);
1299         }
1300     }
1301 
1302     private boolean containsCoordinates(String message, String groupId, String artifactId, String version) {
1303         return message != null
1304                 && (groupId == null || message.contains(groupId))
1305                 && (artifactId == null || message.contains(artifactId))
1306                 && (version == null || message.contains(version));
1307     }
1308 
1309     protected boolean hasModelErrors(ModelProblemCollectorExt problems) {
1310         if (problems instanceof DefaultModelProblemCollector collector) {
1311             return collector.hasErrors();
1312         } else {
1313             // the default execution path only knows the DefaultModelProblemCollector,
1314             // only reason it's not in signature is because it's package private
1315             throw new IllegalStateException();
1316         }
1317     }
1318 
1319     protected boolean hasFatalErrors(ModelProblemCollectorExt problems) {
1320         if (problems instanceof DefaultModelProblemCollector collector) {
1321             return collector.hasFatalErrors();
1322         } else {
1323             // the default execution path only knows the DefaultModelProblemCollector,
1324             // only reason it's not in signature is because it's package private
1325             throw new IllegalStateException();
1326         }
1327     }
1328 }