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 ModelSource expectedParentSource = getParentPomFile( childModel, childSource );
856
857 if ( expectedParentSource == null || ( expectedParentSource instanceof ModelSource2
858 && !pomFile.toURI().equals( ( (ModelSource2) expectedParentSource ).getLocationURI() ) ) )
859 {
860 parentData = readParentExternally( childModel, request, problems );
861 }
862 }
863 }
864
865 Model parentModel = parentData.getModel();
866
867 if ( !"pom".equals( parentModel.getPackaging() ) )
868 {
869 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
870 .setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel )
871 + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"" )
872 .setLocation( parentModel.getLocation( "packaging" ) ) );
873 }
874 }
875 else
876 {
877 parentData = null;
878 }
879
880 return parentData;
881 }
882
883 private ModelData readParentLocally( Model childModel, ModelSource childSource, ModelBuildingRequest request,
884 DefaultModelProblemCollector problems )
885 throws ModelBuildingException
886 {
887 final Parent parent = childModel.getParent();
888 final ModelSource candidateSource;
889 final Model candidateModel;
890 final WorkspaceModelResolver resolver = request.getWorkspaceModelResolver();
891 if ( resolver == null )
892 {
893 candidateSource = getParentPomFile( childModel, childSource );
894
895 if ( candidateSource == null )
896 {
897 return null;
898 }
899
900 File pomFile = null;
901 if ( candidateSource instanceof FileModelSource )
902 {
903 pomFile = ( (FileModelSource) candidateSource ).getPomFile();
904 }
905
906 candidateModel = readModel( candidateSource, pomFile, request, problems );
907 }
908 else
909 {
910 try
911 {
912 candidateModel =
913 resolver.resolveRawModel( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
914 }
915 catch ( UnresolvableModelException e )
916 {
917 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
918 .setMessage( e.getMessage().toString() ).setLocation( parent.getLocation( "" ) ).setException( e ) );
919 throw problems.newModelBuildingException();
920 }
921 if ( candidateModel == null )
922 {
923 return null;
924 }
925 candidateSource = new FileModelSource( candidateModel.getPomFile() );
926 }
927
928
929
930
931
932
933
934 String groupId = candidateModel.getGroupId();
935 if ( groupId == null && candidateModel.getParent() != null )
936 {
937 groupId = candidateModel.getParent().getGroupId();
938 }
939 String artifactId = candidateModel.getArtifactId();
940 String version = candidateModel.getVersion();
941 if ( version == null && candidateModel.getParent() != null )
942 {
943 version = candidateModel.getParent().getVersion();
944 }
945
946 if ( groupId == null || !groupId.equals( parent.getGroupId() ) || artifactId == null
947 || !artifactId.equals( parent.getArtifactId() ) )
948 {
949 StringBuilder buffer = new StringBuilder( 256 );
950 buffer.append( "'parent.relativePath'" );
951 if ( childModel != problems.getRootModel() )
952 {
953 buffer.append( " of POM " ).append( ModelProblemUtils.toSourceHint( childModel ) );
954 }
955 buffer.append( " points at " ).append( groupId ).append( ':' ).append( artifactId );
956 buffer.append( " instead of " ).append( parent.getGroupId() ).append( ':' );
957 buffer.append( parent.getArtifactId() ).append( ", please verify your project structure" );
958
959 problems.setSource( childModel );
960 problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.BASE )
961 .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ) );
962 return null;
963 }
964 if ( version != null && parent.getVersion() != null && !version.equals( parent.getVersion() ) )
965 {
966 try
967 {
968 VersionRange parentRange = VersionRange.createFromVersionSpec( parent.getVersion() );
969 if ( !parentRange.hasRestrictions() )
970 {
971
972 return null;
973 }
974 if ( !parentRange.containsVersion( new DefaultArtifactVersion( version ) ) )
975 {
976
977 return null;
978 }
979
980
981 if ( childModel.getVersion() == null )
982 {
983
984 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
985 .setMessage( "Version must be a constant" ).setLocation( childModel.getLocation( "" ) ) );
986
987 }
988 else
989 {
990 if ( childModel.getVersion().contains( "${" ) )
991 {
992
993 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
994 .setMessage( "Version must be a constant" )
995 .setLocation( childModel.getLocation( "version" ) ) );
996
997 }
998 }
999
1000
1001 }
1002 catch ( InvalidVersionSpecificationException e )
1003 {
1004
1005 return null;
1006 }
1007 }
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018 ModelData parentData = new ModelData( candidateSource, candidateModel, groupId, artifactId, version );
1019
1020 return parentData;
1021 }
1022
1023 private ModelSource getParentPomFile( Model childModel, ModelSource source )
1024 {
1025 if ( !( source instanceof ModelSource2 ) )
1026 {
1027 return null;
1028 }
1029
1030 String parentPath = childModel.getParent().getRelativePath();
1031
1032 if ( parentPath == null || parentPath.length() <= 0 )
1033 {
1034 return null;
1035 }
1036
1037 return ( (ModelSource2) source ).getRelatedSource( parentPath );
1038 }
1039
1040 private ModelData readParentExternally( Model childModel, ModelBuildingRequest request,
1041 DefaultModelProblemCollector problems )
1042 throws ModelBuildingException
1043 {
1044 problems.setSource( childModel );
1045
1046 Parent parent = childModel.getParent().clone();
1047
1048 String groupId = parent.getGroupId();
1049 String artifactId = parent.getArtifactId();
1050 String version = parent.getVersion();
1051
1052 ModelResolver modelResolver = request.getModelResolver();
1053 Objects.requireNonNull( modelResolver,
1054 String.format( "request.modelResolver cannot be null (parent POM %s and POM %s)",
1055 ModelProblemUtils.toId( groupId, artifactId, version ),
1056 ModelProblemUtils.toSourceHint( childModel ) ) );
1057
1058 ModelSource modelSource;
1059 try
1060 {
1061 modelSource = modelResolver.resolveModel( parent );
1062 }
1063 catch ( UnresolvableModelException e )
1064 {
1065
1066 StringBuilder buffer = new StringBuilder( 256 );
1067 buffer.append( "Non-resolvable parent POM" );
1068 if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) )
1069 {
1070 buffer.append( ' ' ).append( ModelProblemUtils.toId( groupId, artifactId, version ) );
1071 }
1072 if ( childModel != problems.getRootModel() )
1073 {
1074 buffer.append( " for " ).append( ModelProblemUtils.toId( childModel ) );
1075 }
1076 buffer.append( ": " ).append( e.getMessage() );
1077 if ( childModel.getProjectDirectory() != null )
1078 {
1079 if ( parent.getRelativePath() == null || parent.getRelativePath().length() <= 0 )
1080 {
1081 buffer.append( " and 'parent.relativePath' points at no local POM" );
1082 }
1083 else
1084 {
1085 buffer.append( " and 'parent.relativePath' points at wrong local POM" );
1086 }
1087 }
1088
1089 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
1090 .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ).setException( e ) );
1091 throw problems.newModelBuildingException();
1092 }
1093
1094 ModelBuildingRequest lenientRequest = request;
1095 if ( request.getValidationLevel() > ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
1096 {
1097 lenientRequest = new FilterModelBuildingRequest( request )
1098 {
1099 @Override
1100 public int getValidationLevel()
1101 {
1102 return ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
1103 }
1104 };
1105 }
1106
1107 Model parentModel = readModel( modelSource, null, lenientRequest, problems );
1108
1109 if ( !parent.getVersion().equals( version ) )
1110 {
1111 if ( childModel.getVersion() == null )
1112 {
1113
1114 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
1115 .setMessage( "Version must be a constant" ).setLocation( childModel.getLocation( "" ) ) );
1116
1117 }
1118 else
1119 {
1120 if ( childModel.getVersion().contains( "${" ) )
1121 {
1122
1123 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
1124 .setMessage( "Version must be a constant" )
1125 .setLocation( childModel.getLocation( "version" ) ) );
1126
1127 }
1128 }
1129
1130
1131 }
1132
1133 ModelData parentData = new ModelData( modelSource, parentModel, parent.getGroupId(), parent.getArtifactId(),
1134 parent.getVersion() );
1135
1136 return parentData;
1137 }
1138
1139 private Model getSuperModel()
1140 {
1141 return superPomProvider.getSuperModel( "4.0.0" ).clone();
1142 }
1143
1144 @SuppressWarnings( "checkstyle:methodlength" )
1145 private void importDependencyManagement( Model model, ModelBuildingRequest request,
1146 DefaultModelProblemCollector problems, Collection<String> importIds )
1147 {
1148 DependencyManagement depMgmt = model.getDependencyManagement();
1149
1150 if ( depMgmt == null )
1151 {
1152 return;
1153 }
1154
1155 String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion();
1156
1157 importIds.add( importing );
1158
1159 final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver();
1160 final ModelResolver modelResolver = request.getModelResolver();
1161
1162 ModelBuildingRequest importRequest = null;
1163
1164 List<DependencyManagement> importMgmts = null;
1165
1166 for ( Iterator<Dependency> it = depMgmt.getDependencies().iterator(); it.hasNext(); )
1167 {
1168 Dependency dependency = it.next();
1169
1170 if ( !"pom".equals( dependency.getType() ) || !"import".equals( dependency.getScope() ) )
1171 {
1172 continue;
1173 }
1174
1175 it.remove();
1176
1177 String groupId = dependency.getGroupId();
1178 String artifactId = dependency.getArtifactId();
1179 String version = dependency.getVersion();
1180
1181 if ( groupId == null || groupId.length() <= 0 )
1182 {
1183 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
1184 .setMessage( "'dependencyManagement.dependencies.dependency.groupId' for "
1185 + dependency.getManagementKey() + " is missing." )
1186 .setLocation( dependency.getLocation( "" ) ) );
1187 continue;
1188 }
1189 if ( artifactId == null || artifactId.length() <= 0 )
1190 {
1191 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
1192 .setMessage( "'dependencyManagement.dependencies.dependency.artifactId' for "
1193 + dependency.getManagementKey() + " is missing." )
1194 .setLocation( dependency.getLocation( "" ) ) );
1195 continue;
1196 }
1197 if ( version == null || version.length() <= 0 )
1198 {
1199 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
1200 .setMessage( "'dependencyManagement.dependencies.dependency.version' for "
1201 + dependency.getManagementKey() + " is missing." )
1202 .setLocation( dependency.getLocation( "" ) ) );
1203 continue;
1204 }
1205
1206 String imported = groupId + ':' + artifactId + ':' + version;
1207
1208 if ( importIds.contains( imported ) )
1209 {
1210 String message = "The dependencies of type=pom and with scope=import form a cycle: ";
1211 for ( String modelId : importIds )
1212 {
1213 message += modelId + " -> ";
1214 }
1215 message += imported;
1216 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( message ) );
1217
1218 continue;
1219 }
1220
1221 DependencyManagement importMgmt = getCache( request.getModelCache(), groupId, artifactId, version,
1222 ModelCacheTag.IMPORT );
1223
1224 if ( importMgmt == null )
1225 {
1226 if ( workspaceResolver == null && modelResolver == null )
1227 {
1228 throw new NullPointerException( String.format(
1229 "request.workspaceModelResolver and request.modelResolver cannot be null"
1230 + " (parent POM %s and POM %s)",
1231 ModelProblemUtils.toId( groupId, artifactId, version ),
1232 ModelProblemUtils.toSourceHint( model ) ) );
1233 }
1234
1235 Model importModel = null;
1236 if ( workspaceResolver != null )
1237 {
1238 try
1239 {
1240 importModel = workspaceResolver.resolveEffectiveModel( groupId, artifactId, version );
1241 }
1242 catch ( UnresolvableModelException e )
1243 {
1244 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
1245 .setMessage( e.getMessage().toString() ).setException( e ) );
1246 continue;
1247 }
1248 }
1249
1250
1251 if ( importModel == null )
1252 {
1253 final ModelSource importSource;
1254 try
1255 {
1256 importSource = modelResolver.resolveModel( groupId, artifactId, version );
1257 }
1258 catch ( UnresolvableModelException e )
1259 {
1260 StringBuilder buffer = new StringBuilder( 256 );
1261 buffer.append( "Non-resolvable import POM" );
1262 if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) )
1263 {
1264 buffer.append( ' ' ).append( ModelProblemUtils.toId( groupId, artifactId, version ) );
1265 }
1266 buffer.append( ": " ).append( e.getMessage() );
1267
1268 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
1269 .setMessage( buffer.toString() ).setLocation( dependency.getLocation( "" ) )
1270 .setException( e ) );
1271 continue;
1272 }
1273
1274 if ( importRequest == null )
1275 {
1276 importRequest = new DefaultModelBuildingRequest();
1277 importRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
1278 importRequest.setModelCache( request.getModelCache() );
1279 importRequest.setSystemProperties( request.getSystemProperties() );
1280 importRequest.setUserProperties( request.getUserProperties() );
1281 importRequest.setLocationTracking( request.isLocationTracking() );
1282 }
1283
1284 importRequest.setModelSource( importSource );
1285 importRequest.setModelResolver( modelResolver.newCopy() );
1286
1287 final ModelBuildingResult importResult;
1288 try
1289 {
1290 importResult = build( importRequest );
1291 }
1292 catch ( ModelBuildingException e )
1293 {
1294 problems.addAll( e.getProblems() );
1295 continue;
1296 }
1297
1298 problems.addAll( importResult.getProblems() );
1299
1300 importModel = importResult.getEffectiveModel();
1301 }
1302
1303 importMgmt = importModel.getDependencyManagement();
1304
1305 if ( importMgmt == null )
1306 {
1307 importMgmt = new DependencyManagement();
1308 }
1309
1310 putCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt );
1311 }
1312
1313 if ( importMgmts == null )
1314 {
1315 importMgmts = new ArrayList<>();
1316 }
1317
1318 importMgmts.add( importMgmt );
1319 }
1320
1321 importIds.remove( importing );
1322
1323 dependencyManagementImporter.importManagement( model, importMgmts, request, problems );
1324 }
1325
1326 private <T> void putCache( ModelCache modelCache, String groupId, String artifactId, String version,
1327 ModelCacheTag<T> tag, T data )
1328 {
1329 if ( modelCache != null )
1330 {
1331 modelCache.put( groupId, artifactId, version, tag.getName(), tag.intoCache( data ) );
1332 }
1333 }
1334
1335 private <T> T getCache( ModelCache modelCache, String groupId, String artifactId, String version,
1336 ModelCacheTag<T> tag )
1337 {
1338 if ( modelCache != null )
1339 {
1340 Object data = modelCache.get( groupId, artifactId, version, tag.getName() );
1341 if ( data != null )
1342 {
1343 return tag.fromCache( tag.getType().cast( data ) );
1344 }
1345 }
1346 return null;
1347 }
1348
1349 private void fireEvent( Model model, ModelBuildingRequest request, ModelProblemCollector problems,
1350 ModelBuildingEventCatapult catapult )
1351 throws ModelBuildingException
1352 {
1353 ModelBuildingListener listener = request.getModelBuildingListener();
1354
1355 if ( listener != null )
1356 {
1357 ModelBuildingEvent event = new DefaultModelBuildingEvent( model, request, problems );
1358
1359 catapult.fire( listener, event );
1360 }
1361 }
1362
1363 private boolean containsCoordinates( String message, String groupId, String artifactId, String version )
1364 {
1365 return message != null && ( groupId == null || message.contains( groupId ) )
1366 && ( artifactId == null || message.contains( artifactId ) )
1367 && ( version == null || message.contains( version ) );
1368 }
1369
1370 protected boolean hasModelErrors( ModelProblemCollectorExt problems )
1371 {
1372 if ( problems instanceof DefaultModelProblemCollector )
1373 {
1374 return ( (DefaultModelProblemCollector) problems ).hasErrors();
1375 }
1376 else
1377 {
1378
1379
1380 throw new IllegalStateException();
1381 }
1382 }
1383
1384 protected boolean hasFatalErrors( ModelProblemCollectorExt problems )
1385 {
1386 if ( problems instanceof DefaultModelProblemCollector )
1387 {
1388 return ( (DefaultModelProblemCollector) problems ).hasFatalErrors();
1389 }
1390 else
1391 {
1392
1393
1394 throw new IllegalStateException();
1395 }
1396 }
1397
1398 }