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