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.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
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
248 DefaultModelBuildingResult result = new DefaultModelBuildingResult();
249
250 DefaultModelProblemCollector problems = new DefaultModelProblemCollector( result );
251
252
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
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
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
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 {
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
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
380 assembleInheritance( lineage, request, problems );
381
382 Model resultModel = resultData.getModel();
383
384 problems.setSource( resultModel );
385 problems.setRootModel( resultModel );
386
387
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
396 parentData.setVersion( interpolatedParent.getVersion() );
397 }
398
399
400 modelUrlNormalizer.normalize( resultModel, request );
401
402
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
440 Model resultModel = result.getEffectiveModel();
441
442 DefaultModelProblemCollector problems = new DefaultModelProblemCollector( result );
443 problems.setSource( resultModel );
444 problems.setRootModel( resultModel );
445
446
447 modelPathTranslator.alignToBaseDirectory( resultModel, resultModel.getProjectDirectory(), request );
448
449
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
462 lifecycleBindingsInjector.injectLifecycleBindings( resultModel, request, problems );
463 }
464
465
466 importDependencyManagement( resultModel, request, problems, imports );
467
468
469 dependencyManagementInjector.injectManagement( resultModel, request, problems );
470
471 modelNormalizer.injectDefaultValues( resultModel, request, problems );
472
473 if ( request.isProcessPlugins() )
474 {
475
476 reportConfigurationExpander.expandPluginConfiguration( resultModel, request, problems );
477
478
479 reportingConverter.convertReporting( resultModel, request, problems );
480
481
482 pluginConfigurationExpander.expandPluginConfiguration( resultModel, request, problems );
483 }
484
485
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
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
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
771 profile.setActivation( activations.get( profile.getId() ) );
772 }
773 }
774
775 private Model interpolateModel( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
776 {
777
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
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
847
848
849
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
931
932
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
973 return null;
974 }
975 if ( !parentRange.containsVersion( new DefaultArtifactVersion( version ) ) )
976 {
977
978 return null;
979 }
980
981
982 if ( childModel.getVersion() == null )
983 {
984
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
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
1002 }
1003 catch ( InvalidVersionSpecificationException e )
1004 {
1005
1006 return null;
1007 }
1008 }
1009
1010
1011
1012
1013
1014
1015
1016
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
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
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
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
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
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
1380
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
1394
1395 throw new IllegalStateException();
1396 }
1397 }
1398
1399 }