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<>());
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                 StringBuilder message = new StringBuilder("The parents form a cycle: ");
362                 for (String modelId : parentIds) {
363                     message.append(modelId);
364                     message.append(" -> ");
365                 }
366                 message.append(parentData.getId());
367 
368                 problems.add(new ModelProblemCollectorRequest(ModelProblem.Severity.FATAL, ModelProblem.Version.BASE)
369                         .setMessage(message.toString()));
370 
371                 throw problems.newModelBuildingException();
372             } else {
373                 currentData = parentData;
374             }
375         }
376 
377         problems.setSource(inputModel);
378         checkPluginVersions(lineage, request, problems);
379 
380         // inheritance assembly
381         assembleInheritance(lineage, request, problems);
382 
383         Model resultModel = resultData.getModel();
384 
385         problems.setSource(resultModel);
386         problems.setRootModel(resultModel);
387 
388         // model interpolation
389         resultModel = interpolateModel(resultModel, request, problems);
390         resultData.setModel(resultModel);
391 
392         if (resultModel.getParent() != null) {
393             final ModelData parentData = lineage.get(1);
394             if (parentData.getVersion() == null || parentData.getVersion().contains("${")) {
395                 final Model interpolatedParent = interpolateModel(parentData.getModel(), request, problems);
396                 // parentData.setModel( interpolatedParent );
397                 parentData.setVersion(interpolatedParent.getVersion());
398             }
399         }
400 
401         // url normalization
402         modelUrlNormalizer.normalize(resultModel, request);
403 
404         // Now the fully interpolated model is available: reconfigure the resolver
405         configureResolver(request.getModelResolver(), resultModel, problems, true);
406 
407         resultData.setGroupId(resultModel.getGroupId());
408         resultData.setArtifactId(resultModel.getArtifactId());
409         resultData.setVersion(resultModel.getVersion());
410 
411         result.setEffectiveModel(resultModel);
412 
413         for (ModelData currentData : lineage) {
414             String modelId = (currentData != superData) ? currentData.getId() : "";
415 
416             result.addModelId(modelId);
417             result.setActivePomProfiles(modelId, currentData.getActiveProfiles());
418             result.setRawModel(modelId, currentData.getRawModel());
419         }
420 
421         if (!request.isTwoPhaseBuilding()) {
422             build(request, result, importIds);
423         }
424 
425         return result;
426     }
427 
428     @FunctionalInterface
429     private interface InterpolateString {
430         String apply(String s) throws InterpolationException;
431     }
432 
433     private List<Profile> getInterpolatedProfiles(
434             Model rawModel, DefaultProfileActivationContext context, DefaultModelProblemCollector problems) {
435         List<Profile> interpolatedActivations = getProfiles(rawModel);
436 
437         if (interpolatedActivations.isEmpty()) {
438             return Collections.emptyList();
439         }
440         RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
441 
442         interpolator.addValueSource(new MapBasedValueSource(context.getProjectProperties()));
443         interpolator.addValueSource(new MapBasedValueSource(context.getUserProperties()));
444         interpolator.addValueSource(new MapBasedValueSource(context.getSystemProperties()));
445 
446         class Interpolation {
447             final InputLocationTracker target;
448 
449             final InterpolateString impl;
450 
451             Interpolation(InputLocationTracker target, InterpolateString impl) {
452                 this.target = target;
453                 this.impl = impl;
454             }
455 
456             void performFor(String value, String locationKey, Consumer<String> mutator) {
457                 if (StringUtils.isEmpty(value)) {
458                     return;
459                 }
460                 try {
461                     mutator.accept(impl.apply(value));
462                 } catch (InterpolationException e) {
463                     problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
464                             .setMessage("Failed to interpolate value " + value + ": " + e.getMessage())
465                             .setLocation(target.getLocation(locationKey))
466                             .setException(e));
467                 }
468             }
469         }
470         for (Profile profile : interpolatedActivations) {
471             Activation activation = profile.getActivation();
472             Optional<Activation> a = Optional.ofNullable(activation);
473             a.map(Activation::getFile).ifPresent(fa -> {
474                 Interpolation nt =
475                         new Interpolation(fa, s -> profileActivationFilePathInterpolator.interpolate(s, context));
476                 nt.performFor(fa.getExists(), "exists", fa::setExists);
477                 nt.performFor(fa.getMissing(), "missing", fa::setMissing);
478             });
479             a.map(Activation::getOs).ifPresent(oa -> {
480                 Interpolation nt = new Interpolation(oa, interpolator::interpolate);
481                 nt.performFor(oa.getArch(), "arch", oa::setArch);
482                 nt.performFor(oa.getFamily(), "family", oa::setFamily);
483                 nt.performFor(oa.getName(), "name", oa::setName);
484                 nt.performFor(oa.getVersion(), "version", oa::setVersion);
485             });
486             a.map(Activation::getProperty).ifPresent(pa -> {
487                 Interpolation nt = new Interpolation(pa, interpolator::interpolate);
488                 nt.performFor(pa.getName(), "name", pa::setName);
489                 nt.performFor(pa.getValue(), "value", pa::setValue);
490             });
491             a.map(Activation::getJdk)
492                     .ifPresent(ja -> new Interpolation(activation, interpolator::interpolate)
493                             .performFor(ja, "jdk", activation::setJdk));
494         }
495         return interpolatedActivations;
496     }
497 
498     @Override
499     public ModelBuildingResult build(ModelBuildingRequest request, ModelBuildingResult result)
500             throws ModelBuildingException {
501         return build(request, result, new LinkedHashSet());
502     }
503 
504     private ModelBuildingResult build(
505             ModelBuildingRequest request, ModelBuildingResult result, Collection<String> imports)
506             throws ModelBuildingException {
507         // phase 2
508         Model resultModel = result.getEffectiveModel();
509 
510         DefaultModelProblemCollector problems = new DefaultModelProblemCollector(result);
511         problems.setSource(resultModel);
512         problems.setRootModel(resultModel);
513 
514         // model path translation
515         modelPathTranslator.alignToBaseDirectory(resultModel, resultModel.getProjectDirectory(), request);
516 
517         // plugin management injection
518         pluginManagementInjector.injectManagement(resultModel, request, problems);
519 
520         fireEvent(resultModel, request, problems, ModelBuildingEventCatapult.BUILD_EXTENSIONS_ASSEMBLED);
521 
522         if (request.isProcessPlugins()) {
523             if (lifecycleBindingsInjector == null) {
524                 throw new IllegalStateException("lifecycle bindings injector is missing");
525             }
526 
527             // lifecycle bindings injection
528             lifecycleBindingsInjector.injectLifecycleBindings(resultModel, request, problems);
529         }
530 
531         // dependency management import
532         importDependencyManagement(resultModel, request, problems, imports);
533 
534         // dependency management injection
535         dependencyManagementInjector.injectManagement(resultModel, request, problems);
536 
537         modelNormalizer.injectDefaultValues(resultModel, request, problems);
538 
539         if (request.isProcessPlugins()) {
540             // reports configuration
541             reportConfigurationExpander.expandPluginConfiguration(resultModel, request, problems);
542 
543             // reports conversion to decoupled site plugin
544             reportingConverter.convertReporting(resultModel, request, problems);
545 
546             // plugins configuration
547             pluginConfigurationExpander.expandPluginConfiguration(resultModel, request, problems);
548         }
549 
550         // effective model validation
551         modelValidator.validateEffectiveModel(resultModel, request, problems);
552 
553         if (hasModelErrors(problems)) {
554             throw problems.newModelBuildingException();
555         }
556 
557         return result;
558     }
559 
560     @Override
561     public Result<? extends Model> buildRawModel(File pomFile, int validationLevel, boolean locationTracking) {
562         final ModelBuildingRequest request = new DefaultModelBuildingRequest()
563                 .setValidationLevel(validationLevel)
564                 .setLocationTracking(locationTracking);
565         final DefaultModelProblemCollector collector =
566                 new DefaultModelProblemCollector(new DefaultModelBuildingResult());
567         try {
568             return newResult(readModel(null, pomFile, request, collector), collector.getProblems());
569         } catch (ModelBuildingException e) {
570             return error(collector.getProblems());
571         }
572     }
573 
574     private Model readModel(
575             ModelSource modelSource, File pomFile, ModelBuildingRequest request, DefaultModelProblemCollector problems)
576             throws ModelBuildingException {
577         Model model;
578 
579         if (modelSource == null) {
580             if (pomFile != null) {
581                 modelSource = new FileModelSource(pomFile);
582             } else {
583                 throw new NullPointerException("neither pomFile nor modelSource can be null");
584             }
585         }
586 
587         problems.setSource(modelSource.getLocation());
588         try {
589             boolean strict = request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
590             InputSource source = request.isLocationTracking() ? new InputSource() : null;
591 
592             Map<String, Object> options = new HashMap<>();
593             options.put(ModelProcessor.IS_STRICT, strict);
594             options.put(ModelProcessor.INPUT_SOURCE, source);
595             options.put(ModelProcessor.SOURCE, modelSource);
596 
597             try {
598                 model = modelProcessor.read(modelSource.getInputStream(), options);
599             } catch (ModelParseException e) {
600                 if (!strict) {
601                     throw e;
602                 }
603 
604                 options.put(ModelProcessor.IS_STRICT, Boolean.FALSE);
605 
606                 try {
607                     model = modelProcessor.read(modelSource.getInputStream(), options);
608                 } catch (ModelParseException ne) {
609                     // still unreadable even in non-strict mode, rethrow original error
610                     throw e;
611                 }
612 
613                 if (pomFile != null) {
614                     problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.V20)
615                             .setMessage("Malformed POM " + modelSource.getLocation() + ": " + e.getMessage())
616                             .setException(e));
617                 } else {
618                     problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.V20)
619                             .setMessage("Malformed POM " + modelSource.getLocation() + ": " + e.getMessage())
620                             .setException(e));
621                 }
622             }
623 
624             if (source != null) {
625                 source.setModelId(ModelProblemUtils.toId(model));
626                 source.setLocation(modelSource.getLocation());
627             }
628         } catch (ModelParseException e) {
629             problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
630                     .setMessage("Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage())
631                     .setException(e));
632             throw problems.newModelBuildingException();
633         } catch (IOException e) {
634             String msg = e.getMessage();
635             if (msg == null || msg.length() <= 0) {
636                 // NOTE: There's java.nio.charset.MalformedInputException and sun.io.MalformedInputException
637                 if (e.getClass().getName().endsWith("MalformedInputException")) {
638                     msg = "Some input bytes do not match the file encoding.";
639                 } else {
640                     msg = e.getClass().getSimpleName();
641                 }
642             }
643             problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
644                     .setMessage("Non-readable POM " + modelSource.getLocation() + ": " + msg)
645                     .setException(e));
646             throw problems.newModelBuildingException();
647         }
648 
649         model.setPomFile(pomFile);
650 
651         problems.setSource(model);
652         modelValidator.validateRawModel(model, request, problems);
653 
654         if (hasFatalErrors(problems)) {
655             throw problems.newModelBuildingException();
656         }
657 
658         return model;
659     }
660 
661     private DefaultProfileActivationContext getProfileActivationContext(ModelBuildingRequest request, Model rawModel) {
662         DefaultProfileActivationContext context = new DefaultProfileActivationContext();
663 
664         context.setActiveProfileIds(request.getActiveProfileIds());
665         context.setInactiveProfileIds(request.getInactiveProfileIds());
666         context.setSystemProperties(request.getSystemProperties());
667         // enrich user properties with project packaging
668         Properties userProperties = request.getUserProperties();
669         userProperties.computeIfAbsent(
670                 (Object) ProfileActivationContext.PROPERTY_NAME_PACKAGING, (p) -> (Object) rawModel.getPackaging());
671         context.setUserProperties(userProperties);
672         context.setProjectDirectory(
673                 (request.getPomFile() != null) ? request.getPomFile().getParentFile() : null);
674 
675         return context;
676     }
677 
678     private void configureResolver(ModelResolver modelResolver, Model model, DefaultModelProblemCollector problems) {
679         configureResolver(modelResolver, model, problems, false);
680     }
681 
682     private void configureResolver(
683             ModelResolver modelResolver,
684             Model model,
685             DefaultModelProblemCollector problems,
686             boolean replaceRepositories) {
687         if (modelResolver == null) {
688             return;
689         }
690 
691         problems.setSource(model);
692 
693         List<Repository> repositories = model.getRepositories();
694 
695         for (Repository repository : repositories) {
696             try {
697                 modelResolver.addRepository(repository, replaceRepositories);
698             } catch (InvalidRepositoryException e) {
699                 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
700                         .setMessage("Invalid repository " + repository.getId() + ": " + e.getMessage())
701                         .setLocation(repository.getLocation(""))
702                         .setException(e));
703             }
704         }
705     }
706 
707     private void checkPluginVersions(
708             List<ModelData> lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
709         if (request.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
710             return;
711         }
712 
713         Map<String, Plugin> plugins = new HashMap<>();
714         Map<String, String> versions = new HashMap<>();
715         Map<String, String> managedVersions = new HashMap<>();
716 
717         for (int i = lineage.size() - 1; i >= 0; i--) {
718             Model model = lineage.get(i).getModel();
719             Build build = model.getBuild();
720             if (build != null) {
721                 for (Plugin plugin : build.getPlugins()) {
722                     String key = plugin.getKey();
723                     if (versions.get(key) == null) {
724                         versions.put(key, plugin.getVersion());
725                         plugins.put(key, plugin);
726                     }
727                 }
728                 PluginManagement mgmt = build.getPluginManagement();
729                 if (mgmt != null) {
730                     for (Plugin plugin : mgmt.getPlugins()) {
731                         String key = plugin.getKey();
732                         if (managedVersions.get(key) == null) {
733                             managedVersions.put(key, plugin.getVersion());
734                         }
735                     }
736                 }
737             }
738         }
739 
740         for (String key : versions.keySet()) {
741             if (versions.get(key) == null && managedVersions.get(key) == null) {
742                 InputLocation location = plugins.get(key).getLocation("");
743                 problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.V20)
744                         .setMessage("'build.plugins.plugin.version' for " + key + " is missing.")
745                         .setLocation(location));
746             }
747         }
748     }
749 
750     private void assembleInheritance(
751             List<ModelData> lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
752         for (int i = lineage.size() - 2; i >= 0; i--) {
753             Model parent = lineage.get(i + 1).getModel();
754             Model child = lineage.get(i).getModel();
755             inheritanceAssembler.assembleModelInheritance(child, parent, request, problems);
756         }
757     }
758 
759     private List<Profile> getProfiles(Model model) {
760         ArrayList<Profile> profiles = new ArrayList<>();
761         for (Profile profile : model.getProfiles()) {
762             profile = profile.clone();
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);
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())
800                 .forEach(i -> interpolatedProfiles
801                         .get(i)
802                         .setActivation(originalProfiles.get(i).getActivation()));
803 
804         return interpolatedModel;
805     }
806 
807     private ModelData readParent(
808             Model childModel,
809             ModelSource childSource,
810             ModelBuildingRequest request,
811             DefaultModelProblemCollector problems)
812             throws ModelBuildingException {
813         ModelData parentData;
814 
815         Parent parent = childModel.getParent();
816 
817         if (parent != null) {
818             String groupId = parent.getGroupId();
819             String artifactId = parent.getArtifactId();
820             String version = parent.getVersion();
821 
822             parentData = getCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW);
823 
824             if (parentData == null) {
825                 parentData = readParentLocally(childModel, childSource, request, problems);
826 
827                 if (parentData == null) {
828                     parentData = readParentExternally(childModel, request, problems);
829                 }
830 
831                 putCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW, parentData);
832             } else {
833                 /*
834                  * NOTE: This is a sanity check of the cache hit. If the cached parent POM was locally resolved, the
835                  * child's <relativePath> should point at that parent, too. If it doesn't, we ignore the cache and
836                  * resolve externally, to mimic the behavior if the cache didn't exist in the first place. Otherwise,
837                  * the cache would obscure a bad POM.
838                  */
839 
840                 File pomFile = parentData.getModel().getPomFile();
841                 if (pomFile != null) {
842                     FileModelSource pomSource = new FileModelSource(pomFile);
843                     ModelSource expectedParentSource = getParentPomFile(childModel, childSource);
844 
845                     if (expectedParentSource == null
846                             || (expectedParentSource instanceof ModelSource2
847                                     && !pomSource.equals(expectedParentSource))) {
848                         parentData = readParentExternally(childModel, request, problems);
849                     }
850                 }
851             }
852 
853             Model parentModel = parentData.getModel();
854 
855             if (!"pom".equals(parentModel.getPackaging())) {
856                 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
857                         .setMessage("Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint(parentModel)
858                                 + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"")
859                         .setLocation(parentModel.getLocation("packaging")));
860             }
861         } else {
862             parentData = null;
863         }
864 
865         return parentData;
866     }
867 
868     private ModelData readParentLocally(
869             Model childModel,
870             ModelSource childSource,
871             ModelBuildingRequest request,
872             DefaultModelProblemCollector problems)
873             throws ModelBuildingException {
874         final Parent parent = childModel.getParent();
875         final ModelSource candidateSource;
876         final Model candidateModel;
877         final WorkspaceModelResolver resolver = request.getWorkspaceModelResolver();
878         if (resolver == null) {
879             candidateSource = getParentPomFile(childModel, childSource);
880 
881             if (candidateSource == null) {
882                 return null;
883             }
884 
885             File pomFile = null;
886             if (candidateSource instanceof FileModelSource source) {
887                 pomFile = source.getPomFile();
888             }
889 
890             candidateModel = readModel(candidateSource, pomFile, request, problems);
891         } else {
892             try {
893                 candidateModel =
894                         resolver.resolveRawModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
895             } catch (UnresolvableModelException e) {
896                 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE) //
897                         .setMessage(e.getMessage())
898                         .setLocation(parent.getLocation(""))
899                         .setException(e));
900                 throw problems.newModelBuildingException();
901             }
902             if (candidateModel == null) {
903                 return null;
904             }
905             candidateSource = new FileModelSource(candidateModel.getPomFile());
906         }
907 
908         //
909         // TODO jvz Why isn't all this checking the job of the duty of the workspace resolver, we know that we
910         // have a model that is suitable, yet more checks are done here and the one for the version is problematic
911         // before because with parents as ranges it will never work in this scenario.
912         //
913 
914         String groupId = candidateModel.getGroupId();
915         if (groupId == null && candidateModel.getParent() != null) {
916             groupId = candidateModel.getParent().getGroupId();
917         }
918         String artifactId = candidateModel.getArtifactId();
919         String version = candidateModel.getVersion();
920         if (version == null && candidateModel.getParent() != null) {
921             version = candidateModel.getParent().getVersion();
922         }
923 
924         if (groupId == null
925                 || !groupId.equals(parent.getGroupId())
926                 || artifactId == null
927                 || !artifactId.equals(parent.getArtifactId())) {
928             StringBuilder buffer = new StringBuilder(256);
929             buffer.append("'parent.relativePath'");
930             if (childModel != problems.getRootModel()) {
931                 buffer.append(" of POM ").append(ModelProblemUtils.toSourceHint(childModel));
932             }
933             buffer.append(" points at ").append(groupId).append(':').append(artifactId);
934             buffer.append(" instead of ").append(parent.getGroupId()).append(':');
935             buffer.append(parent.getArtifactId()).append(", please verify your project structure");
936 
937             problems.setSource(childModel);
938             problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.BASE)
939                     .setMessage(buffer.toString())
940                     .setLocation(parent.getLocation("")));
941             return null;
942         }
943         if (version != null && parent.getVersion() != null && !version.equals(parent.getVersion())) {
944             try {
945                 VersionRange parentRange = VersionRange.createFromVersionSpec(parent.getVersion());
946                 if (!parentRange.hasRestrictions()) {
947                     // the parent version is not a range, we have version skew, drop back to resolution from repo
948                     return null;
949                 }
950                 if (!parentRange.containsVersion(new DefaultArtifactVersion(version))) {
951                     // version skew drop back to resolution from the repository
952                     return null;
953                 }
954 
955                 // Validate versions aren't inherited when using parent ranges the same way as when read externally.
956                 String rawChildModelVersion = childModel.getVersion();
957 
958                 if (rawChildModelVersion == null) {
959                     // Message below is checked for in the MNG-2199 core IT.
960                     problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
961                             .setMessage("Version must be a constant")
962                             .setLocation(childModel.getLocation("")));
963 
964                 } else {
965                     if (rawChildVersionReferencesParent(rawChildModelVersion)) {
966                         // Message below is checked for in the MNG-2199 core IT.
967                         problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
968                                 .setMessage("Version must be a constant")
969                                 .setLocation(childModel.getLocation("version")));
970                     }
971                 }
972 
973                 // MNG-2199: What else to check here ?
974             } catch (InvalidVersionSpecificationException e) {
975                 // invalid version range, so drop back to resolution from the repository
976                 return null;
977             }
978         }
979 
980         //
981         // Here we just need to know that a version is fine to use but this validation we can do in our workspace
982         // resolver.
983         //
984 
985         /*
986          * if ( version == null || !version.equals( parent.getVersion() ) ) { return null; }
987          */
988 
989         ModelData parentData = new ModelData(candidateSource, candidateModel, groupId, artifactId, version);
990 
991         return parentData;
992     }
993 
994     private boolean rawChildVersionReferencesParent(String rawChildModelVersion) {
995         return rawChildModelVersion.equals("${pom.version}")
996                 || rawChildModelVersion.equals("${project.version}")
997                 || rawChildModelVersion.equals("${pom.parent.version}")
998                 || rawChildModelVersion.equals("${project.parent.version}");
999     }
1000 
1001     private ModelSource getParentPomFile(Model childModel, ModelSource source) {
1002         if (!(source instanceof ModelSource2)) {
1003             return null;
1004         }
1005 
1006         String parentPath = childModel.getParent().getRelativePath();
1007         if (parentPath == null) {
1008             parentPath = "../pom.xml";
1009         }
1010 
1011         if (parentPath.length() <= 0) {
1012             return null;
1013         }
1014 
1015         return ((ModelSource2) source).getRelatedSource(parentPath);
1016     }
1017 
1018     private ModelData readParentExternally(
1019             Model childModel, ModelBuildingRequest request, DefaultModelProblemCollector problems)
1020             throws ModelBuildingException {
1021         problems.setSource(childModel);
1022 
1023         Parent parent = childModel.getParent().clone();
1024 
1025         String groupId = parent.getGroupId();
1026         String artifactId = parent.getArtifactId();
1027         String version = parent.getVersion();
1028 
1029         ModelResolver modelResolver = request.getModelResolver();
1030         Objects.requireNonNull(
1031                 modelResolver,
1032                 String.format(
1033                         "request.modelResolver cannot be null (parent POM %s and POM %s)",
1034                         ModelProblemUtils.toId(groupId, artifactId, version),
1035                         ModelProblemUtils.toSourceHint(childModel)));
1036 
1037         ModelSource modelSource;
1038         try {
1039             modelSource = modelResolver.resolveModel(parent);
1040         } catch (UnresolvableModelException e) {
1041             // Message below is checked for in the MNG-2199 core IT.
1042             StringBuilder buffer = new StringBuilder(256);
1043             buffer.append("Non-resolvable parent POM");
1044             if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
1045                 buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
1046             }
1047             if (childModel != problems.getRootModel()) {
1048                 buffer.append(" for ").append(ModelProblemUtils.toId(childModel));
1049             }
1050             buffer.append(": ").append(e.getMessage());
1051             if (childModel.getProjectDirectory() != null) {
1052                 if (parent.getRelativePath() == null || parent.getRelativePath().length() <= 0) {
1053                     buffer.append(" and 'parent.relativePath' points at no local POM");
1054                 } else {
1055                     buffer.append(" and 'parent.relativePath' points at wrong local POM");
1056                 }
1057             }
1058 
1059             problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
1060                     .setMessage(buffer.toString())
1061                     .setLocation(parent.getLocation(""))
1062                     .setException(e));
1063             throw problems.newModelBuildingException();
1064         }
1065 
1066         ModelBuildingRequest lenientRequest = request;
1067         if (request.getValidationLevel() > ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
1068             lenientRequest = new FilterModelBuildingRequest(request) {
1069                 @Override
1070                 public int getValidationLevel() {
1071                     return ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
1072                 }
1073             };
1074         }
1075 
1076         Model parentModel = readModel(modelSource, null, lenientRequest, problems);
1077 
1078         if (!parent.getVersion().equals(version)) {
1079             String rawChildModelVersion = childModel.getVersion();
1080 
1081             if (rawChildModelVersion == null) {
1082                 // Message below is checked for in the MNG-2199 core IT.
1083                 problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
1084                         .setMessage("Version must be a constant")
1085                         .setLocation(childModel.getLocation("")));
1086 
1087             } else {
1088                 if (rawChildVersionReferencesParent(rawChildModelVersion)) {
1089                     // Message below is checked for in the MNG-2199 core IT.
1090                     problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
1091                             .setMessage("Version must be a constant")
1092                             .setLocation(childModel.getLocation("version")));
1093                 }
1094             }
1095 
1096             // MNG-2199: What else to check here ?
1097         }
1098 
1099         ModelData parentData = new ModelData(
1100                 modelSource, parentModel, parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
1101 
1102         return parentData;
1103     }
1104 
1105     private Model getSuperModel() {
1106         return superPomProvider.getSuperModel("4.0.0").clone();
1107     }
1108 
1109     @SuppressWarnings("checkstyle:methodlength")
1110     private void importDependencyManagement(
1111             Model model,
1112             ModelBuildingRequest request,
1113             DefaultModelProblemCollector problems,
1114             Collection<String> importIds) {
1115         DependencyManagement depMgmt = model.getDependencyManagement();
1116 
1117         if (depMgmt == null) {
1118             return;
1119         }
1120 
1121         String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion();
1122 
1123         importIds.add(importing);
1124 
1125         final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver();
1126         final ModelResolver modelResolver = request.getModelResolver();
1127 
1128         ModelBuildingRequest importRequest = null;
1129 
1130         List<DependencyManagement> importMgmts = null;
1131 
1132         for (Iterator<Dependency> it = depMgmt.getDependencies().iterator(); it.hasNext(); ) {
1133             Dependency dependency = it.next();
1134 
1135             if (!"pom".equals(dependency.getType()) || !"import".equals(dependency.getScope())) {
1136                 continue;
1137             }
1138 
1139             it.remove();
1140 
1141             String groupId = dependency.getGroupId();
1142             String artifactId = dependency.getArtifactId();
1143             String version = dependency.getVersion();
1144 
1145             if (groupId == null || groupId.length() <= 0) {
1146                 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1147                         .setMessage("'dependencyManagement.dependencies.dependency.groupId' for "
1148                                 + dependency.getManagementKey() + " is missing.")
1149                         .setLocation(dependency.getLocation("")));
1150                 continue;
1151             }
1152             if (artifactId == null || artifactId.length() <= 0) {
1153                 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1154                         .setMessage("'dependencyManagement.dependencies.dependency.artifactId' for "
1155                                 + dependency.getManagementKey() + " is missing.")
1156                         .setLocation(dependency.getLocation("")));
1157                 continue;
1158             }
1159             if (version == null || version.length() <= 0) {
1160                 problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1161                         .setMessage("'dependencyManagement.dependencies.dependency.version' for "
1162                                 + dependency.getManagementKey() + " is missing.")
1163                         .setLocation(dependency.getLocation("")));
1164                 continue;
1165             }
1166 
1167             String imported = groupId + ':' + artifactId + ':' + version;
1168 
1169             if (importIds.contains(imported)) {
1170                 StringBuilder message =
1171                         new StringBuilder("The dependencies of type=pom and with scope=import form a cycle: ");
1172                 for (String modelId : importIds) {
1173                     message.append(modelId);
1174                     message.append(" -> ");
1175                 }
1176                 message.append(imported);
1177                 problems.add(
1178                         new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE).setMessage(message.toString()));
1179 
1180                 continue;
1181             }
1182 
1183             DependencyManagement importMgmt =
1184                     getCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT);
1185 
1186             if (importMgmt == null) {
1187                 if (workspaceResolver == null && modelResolver == null) {
1188                     throw new NullPointerException(String.format(
1189                             "request.workspaceModelResolver and request.modelResolver cannot be null"
1190                                     + " (parent POM %s and POM %s)",
1191                             ModelProblemUtils.toId(groupId, artifactId, version),
1192                             ModelProblemUtils.toSourceHint(model)));
1193                 }
1194 
1195                 Model importModel = null;
1196                 if (workspaceResolver != null) {
1197                     try {
1198                         importModel = workspaceResolver.resolveEffectiveModel(groupId, artifactId, version);
1199                     } catch (UnresolvableModelException e) {
1200                         problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
1201                                 .setMessage(e.getMessage())
1202                                 .setException(e));
1203                         continue;
1204                     }
1205                 }
1206 
1207                 // no workspace resolver or workspace resolver returned null (i.e. model not in workspace)
1208                 if (importModel == null) {
1209                     final ModelSource importSource;
1210                     try {
1211                         importSource = modelResolver.resolveModel(groupId, artifactId, version);
1212                     } catch (UnresolvableModelException e) {
1213                         StringBuilder buffer = new StringBuilder(256);
1214                         buffer.append("Non-resolvable import POM");
1215                         if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
1216                             buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
1217                         }
1218                         buffer.append(": ").append(e.getMessage());
1219 
1220                         problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
1221                                 .setMessage(buffer.toString())
1222                                 .setLocation(dependency.getLocation(""))
1223                                 .setException(e));
1224                         continue;
1225                     }
1226 
1227                     if (importRequest == null) {
1228                         importRequest = new DefaultModelBuildingRequest();
1229                         importRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
1230                         importRequest.setModelCache(request.getModelCache());
1231                         importRequest.setSystemProperties(request.getSystemProperties());
1232                         importRequest.setUserProperties(request.getUserProperties());
1233                         importRequest.setLocationTracking(request.isLocationTracking());
1234                     }
1235 
1236                     importRequest.setModelSource(importSource);
1237                     importRequest.setModelResolver(modelResolver.newCopy());
1238 
1239                     final ModelBuildingResult importResult;
1240                     try {
1241                         importResult = build(importRequest, importIds);
1242                     } catch (ModelBuildingException e) {
1243                         problems.addAll(e.getProblems());
1244                         continue;
1245                     }
1246 
1247                     problems.addAll(importResult.getProblems());
1248 
1249                     importModel = importResult.getEffectiveModel();
1250                 }
1251 
1252                 importMgmt = importModel.getDependencyManagement();
1253 
1254                 if (importMgmt == null) {
1255                     importMgmt = new DependencyManagement();
1256                 }
1257 
1258                 putCache(request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt);
1259             }
1260 
1261             if (importMgmts == null) {
1262                 importMgmts = new ArrayList<>();
1263             }
1264 
1265             importMgmts.add(importMgmt);
1266         }
1267 
1268         importIds.remove(importing);
1269 
1270         dependencyManagementImporter.importManagement(model, importMgmts, request, problems);
1271     }
1272 
1273     private <T> void putCache(
1274             ModelCache modelCache, String groupId, String artifactId, String version, ModelCacheTag<T> tag, T data) {
1275         if (modelCache != null) {
1276             modelCache.put(groupId, artifactId, version, tag.getName(), tag.intoCache(data));
1277         }
1278     }
1279 
1280     private <T> T getCache(
1281             ModelCache modelCache, String groupId, String artifactId, String version, ModelCacheTag<T> tag) {
1282         if (modelCache != null) {
1283             Object data = modelCache.get(groupId, artifactId, version, tag.getName());
1284             if (data != null) {
1285                 return tag.fromCache(tag.getType().cast(data));
1286             }
1287         }
1288         return null;
1289     }
1290 
1291     private void fireEvent(
1292             Model model,
1293             ModelBuildingRequest request,
1294             ModelProblemCollector problems,
1295             ModelBuildingEventCatapult catapult) {
1296         ModelBuildingListener listener = request.getModelBuildingListener();
1297 
1298         if (listener != null) {
1299             ModelBuildingEvent event = new DefaultModelBuildingEvent(model, request, problems);
1300 
1301             catapult.fire(listener, event);
1302         }
1303     }
1304 
1305     private boolean containsCoordinates(String message, String groupId, String artifactId, String version) {
1306         return message != null
1307                 && (groupId == null || message.contains(groupId))
1308                 && (artifactId == null || message.contains(artifactId))
1309                 && (version == null || message.contains(version));
1310     }
1311 
1312     protected boolean hasModelErrors(ModelProblemCollectorExt problems) {
1313         if (problems instanceof DefaultModelProblemCollector collector) {
1314             return collector.hasErrors();
1315         } else {
1316             // the default execution path only knows the DefaultModelProblemCollector,
1317             // only reason it's not in signature is because it's package private
1318             throw new IllegalStateException();
1319         }
1320     }
1321 
1322     protected boolean hasFatalErrors(ModelProblemCollectorExt problems) {
1323         if (problems instanceof DefaultModelProblemCollector collector) {
1324             return collector.hasFatalErrors();
1325         } else {
1326             // the default execution path only knows the DefaultModelProblemCollector,
1327             // only reason it's not in signature is because it's package private
1328             throw new IllegalStateException();
1329         }
1330     }
1331 }