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