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