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.commons.lang3.Validate;
24 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
25 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
26 import org.apache.maven.artifact.versioning.VersionRange;
27 import org.apache.maven.model.Activation;
28 import org.apache.maven.model.Build;
29 import org.apache.maven.model.Dependency;
30 import org.apache.maven.model.DependencyManagement;
31 import org.apache.maven.model.InputLocation;
32 import org.apache.maven.model.InputSource;
33 import org.apache.maven.model.Model;
34 import org.apache.maven.model.Parent;
35 import org.apache.maven.model.Plugin;
36 import org.apache.maven.model.PluginManagement;
37 import org.apache.maven.model.Profile;
38 import org.apache.maven.model.Repository;
39 import org.apache.maven.model.building.ModelProblem.Severity;
40 import org.apache.maven.model.building.ModelProblem.Version;
41 import org.apache.maven.model.composition.DependencyManagementImporter;
42 import org.apache.maven.model.inheritance.InheritanceAssembler;
43 import org.apache.maven.model.interpolation.ModelInterpolator;
44 import org.apache.maven.model.io.ModelParseException;
45 import org.apache.maven.model.management.DependencyManagementInjector;
46 import org.apache.maven.model.management.PluginManagementInjector;
47 import org.apache.maven.model.normalization.ModelNormalizer;
48 import org.apache.maven.model.path.ModelPathTranslator;
49 import org.apache.maven.model.path.ModelUrlNormalizer;
50 import org.apache.maven.model.plugin.LifecycleBindingsInjector;
51 import org.apache.maven.model.plugin.PluginConfigurationExpander;
52 import org.apache.maven.model.plugin.ReportConfigurationExpander;
53 import org.apache.maven.model.plugin.ReportingConverter;
54 import org.apache.maven.model.profile.DefaultProfileActivationContext;
55 import org.apache.maven.model.profile.ProfileInjector;
56 import org.apache.maven.model.profile.ProfileSelector;
57 import org.apache.maven.model.resolution.InvalidRepositoryException;
58 import org.apache.maven.model.resolution.ModelResolver;
59 import org.apache.maven.model.resolution.UnresolvableModelException;
60 import org.apache.maven.model.resolution.WorkspaceModelResolver;
61 import org.apache.maven.model.superpom.SuperPomProvider;
62 import org.apache.maven.model.validation.ModelValidator;
63 import org.codehaus.plexus.component.annotations.Component;
64 import org.codehaus.plexus.component.annotations.Requirement;
65 import org.codehaus.plexus.interpolation.MapBasedValueSource;
66 import org.codehaus.plexus.interpolation.StringSearchInterpolator;
67
68 import java.io.File;
69 import java.io.IOException;
70 import java.util.ArrayList;
71 import java.util.Collection;
72 import java.util.HashMap;
73 import java.util.Iterator;
74 import java.util.LinkedHashSet;
75 import java.util.List;
76 import java.util.Map;
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
392 modelUrlNormalizer.normalize( resultModel, request );
393
394
395 configureResolver( request.getModelResolver(), resultModel, problems, true );
396
397 resultData.setGroupId( resultModel.getGroupId() );
398 resultData.setArtifactId( resultModel.getArtifactId() );
399 resultData.setVersion( resultModel.getVersion() );
400
401 result.setEffectiveModel( resultModel );
402
403 for ( ModelData currentData : lineage )
404 {
405 String modelId = ( currentData != superData ) ? currentData.getId() : "";
406
407 result.addModelId( modelId );
408 result.setActivePomProfiles( modelId, currentData.getActiveProfiles() );
409 result.setRawModel( modelId, currentData.getRawModel() );
410 }
411
412 if ( !request.isTwoPhaseBuilding() )
413 {
414 build( request, result );
415 }
416
417 return result;
418 }
419
420 @Override
421 public ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result )
422 throws ModelBuildingException
423 {
424 return build( request, result, new LinkedHashSet<String>() );
425 }
426
427 private ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result,
428 Collection<String> imports )
429 throws ModelBuildingException
430 {
431
432 Model resultModel = result.getEffectiveModel();
433
434 DefaultModelProblemCollector problems = new DefaultModelProblemCollector( result );
435 problems.setSource( resultModel );
436 problems.setRootModel( resultModel );
437
438
439 modelPathTranslator.alignToBaseDirectory( resultModel, resultModel.getProjectDirectory(), request );
440
441
442 pluginManagementInjector.injectManagement( resultModel, request, problems );
443
444 fireEvent( resultModel, request, problems, ModelBuildingEventCatapult.BUILD_EXTENSIONS_ASSEMBLED );
445
446 if ( request.isProcessPlugins() )
447 {
448 if ( lifecycleBindingsInjector == null )
449 {
450 throw new IllegalStateException( "lifecycle bindings injector is missing" );
451 }
452
453
454 lifecycleBindingsInjector.injectLifecycleBindings( resultModel, request, problems );
455 }
456
457
458 importDependencyManagement( resultModel, request, problems, imports );
459
460
461 dependencyManagementInjector.injectManagement( resultModel, request, problems );
462
463 modelNormalizer.injectDefaultValues( resultModel, request, problems );
464
465 if ( request.isProcessPlugins() )
466 {
467
468 reportConfigurationExpander.expandPluginConfiguration( resultModel, request, problems );
469
470
471 reportingConverter.convertReporting( resultModel, request, problems );
472
473
474 pluginConfigurationExpander.expandPluginConfiguration( resultModel, request, problems );
475 }
476
477
478 modelValidator.validateEffectiveModel( resultModel, request, problems );
479
480 if ( hasModelErrors( problems ) )
481 {
482 throw problems.newModelBuildingException();
483 }
484
485 return result;
486 }
487
488 @Override
489 public Result<? extends Model> buildRawModel( File pomFile, int validationLevel, boolean locationTracking )
490 {
491 final ModelBuildingRequest request = new DefaultModelBuildingRequest().setValidationLevel( validationLevel )
492 .setLocationTracking( locationTracking );
493 final DefaultModelProblemCollector collector =
494 new DefaultModelProblemCollector( new DefaultModelBuildingResult() );
495 try
496 {
497 return newResult( readModel( null, pomFile, request, collector ), collector.getProblems() );
498 }
499 catch ( ModelBuildingException e )
500 {
501 return error( collector.getProblems() );
502 }
503 }
504
505 private Model readModel( ModelSource modelSource, File pomFile, ModelBuildingRequest request,
506 DefaultModelProblemCollector problems )
507 throws ModelBuildingException
508 {
509 Model model;
510
511 if ( modelSource == null )
512 {
513 if ( pomFile != null )
514 {
515 modelSource = new FileModelSource( pomFile );
516 }
517 else
518 {
519 throw new NullPointerException( "neither pomFile nor modelSource can be null" );
520 }
521 }
522
523 problems.setSource( modelSource.getLocation() );
524 try
525 {
526 boolean strict = request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
527 InputSource source = request.isLocationTracking() ? new InputSource() : null;
528
529 Map<String, Object> options = new HashMap<>();
530 options.put( ModelProcessor.IS_STRICT, strict );
531 options.put( ModelProcessor.INPUT_SOURCE, source );
532 options.put( ModelProcessor.SOURCE, modelSource );
533
534 try
535 {
536 model = modelProcessor.read( modelSource.getInputStream(), options );
537 }
538 catch ( ModelParseException e )
539 {
540 if ( !strict )
541 {
542 throw e;
543 }
544
545 options.put( ModelProcessor.IS_STRICT, Boolean.FALSE );
546
547 try
548 {
549 model = modelProcessor.read( modelSource.getInputStream(), options );
550 }
551 catch ( ModelParseException ne )
552 {
553
554 throw e;
555 }
556
557 if ( pomFile != null )
558 {
559 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.V20 )
560 .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() )
561 .setException( e ) );
562 }
563 else
564 {
565 problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 )
566 .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() )
567 .setException( e ) );
568 }
569 }
570
571 if ( source != null )
572 {
573 source.setModelId( ModelProblemUtils.toId( model ) );
574 source.setLocation( modelSource.getLocation() );
575 }
576 }
577 catch ( ModelParseException e )
578 {
579 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
580 .setMessage( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage() )
581 .setException( e ) );
582 throw problems.newModelBuildingException();
583 }
584 catch ( IOException e )
585 {
586 String msg = e.getMessage();
587 if ( msg == null || msg.length() <= 0 )
588 {
589
590 if ( e.getClass().getName().endsWith( "MalformedInputException" ) )
591 {
592 msg = "Some input bytes do not match the file encoding.";
593 }
594 else
595 {
596 msg = e.getClass().getSimpleName();
597 }
598 }
599 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
600 .setMessage( "Non-readable POM " + modelSource.getLocation() + ": " + msg ).setException( e ) );
601 throw problems.newModelBuildingException();
602 }
603
604 model.setPomFile( pomFile );
605
606 problems.setSource( model );
607 modelValidator.validateRawModel( model, request, problems );
608
609 if ( hasFatalErrors( problems ) )
610 {
611 throw problems.newModelBuildingException();
612 }
613
614 return model;
615 }
616
617 private DefaultProfileActivationContext getProfileActivationContext( ModelBuildingRequest request )
618 {
619 DefaultProfileActivationContext context = new DefaultProfileActivationContext();
620
621 context.setActiveProfileIds( request.getActiveProfileIds() );
622 context.setInactiveProfileIds( request.getInactiveProfileIds() );
623 context.setSystemProperties( request.getSystemProperties() );
624 context.setUserProperties( request.getUserProperties() );
625 context.setProjectDirectory( ( request.getPomFile() != null ) ? request.getPomFile().getParentFile() : null );
626
627 return context;
628 }
629
630 private void configureResolver( ModelResolver modelResolver, Model model, DefaultModelProblemCollector problems )
631 {
632 configureResolver( modelResolver, model, problems, false );
633 }
634
635 private void configureResolver( ModelResolver modelResolver, Model model, DefaultModelProblemCollector problems,
636 boolean replaceRepositories )
637 {
638 if ( modelResolver == null )
639 {
640 return;
641 }
642
643 problems.setSource( model );
644
645 List<Repository> repositories = model.getRepositories();
646
647 for ( Repository repository : repositories )
648 {
649 try
650 {
651 modelResolver.addRepository( repository, replaceRepositories );
652 }
653 catch ( InvalidRepositoryException e )
654 {
655 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
656 .setMessage( "Invalid repository " + repository.getId() + ": " + e.getMessage() )
657 .setLocation( repository.getLocation( "" ) ).setException( e ) );
658 }
659 }
660 }
661
662 private void checkPluginVersions( List<ModelData> lineage, ModelBuildingRequest request,
663 ModelProblemCollector problems )
664 {
665 if ( request.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
666 {
667 return;
668 }
669
670 Map<String, Plugin> plugins = new HashMap<>();
671 Map<String, String> versions = new HashMap<>();
672 Map<String, String> managedVersions = new HashMap<>();
673
674 for ( int i = lineage.size() - 1; i >= 0; i-- )
675 {
676 Model model = lineage.get( i ).getModel();
677 Build build = model.getBuild();
678 if ( build != null )
679 {
680 for ( Plugin plugin : build.getPlugins() )
681 {
682 String key = plugin.getKey();
683 if ( versions.get( key ) == null )
684 {
685 versions.put( key, plugin.getVersion() );
686 plugins.put( key, plugin );
687 }
688 }
689 PluginManagement mgmt = build.getPluginManagement();
690 if ( mgmt != null )
691 {
692 for ( Plugin plugin : mgmt.getPlugins() )
693 {
694 String key = plugin.getKey();
695 if ( managedVersions.get( key ) == null )
696 {
697 managedVersions.put( key, plugin.getVersion() );
698 }
699 }
700 }
701 }
702 }
703
704 for ( String key : versions.keySet() )
705 {
706 if ( versions.get( key ) == null && managedVersions.get( key ) == null )
707 {
708 InputLocation location = plugins.get( key ).getLocation( "" );
709 problems
710 .add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 )
711 .setMessage( "'build.plugins.plugin.version' for " + key + " is missing." )
712 .setLocation( location ) );
713 }
714 }
715 }
716
717 private void assembleInheritance( List<ModelData> lineage, ModelBuildingRequest request,
718 ModelProblemCollector problems )
719 {
720 for ( int i = lineage.size() - 2; i >= 0; i-- )
721 {
722 Model parent = lineage.get( i + 1 ).getModel();
723 Model child = lineage.get( i ).getModel();
724 inheritanceAssembler.assembleModelInheritance( child, parent, request, problems );
725 }
726 }
727
728 private Map<String, Activation> getProfileActivations( Model model, boolean clone )
729 {
730 Map<String, Activation> activations = new HashMap<>();
731 for ( Profile profile : model.getProfiles() )
732 {
733 Activation activation = profile.getActivation();
734
735 if ( activation == null )
736 {
737 continue;
738 }
739
740 if ( clone )
741 {
742 activation = activation.clone();
743 }
744
745 activations.put( profile.getId(), activation );
746 }
747
748 return activations;
749 }
750
751 private void injectProfileActivations( Model model, Map<String, Activation> activations )
752 {
753 for ( Profile profile : model.getProfiles() )
754 {
755 Activation activation = profile.getActivation();
756
757 if ( activation == null )
758 {
759 continue;
760 }
761
762
763 profile.setActivation( activations.get( profile.getId() ) );
764 }
765 }
766
767 private Model interpolateModel( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
768 {
769
770 Map<String, Activation> originalActivations = getProfileActivations( model, true );
771
772 Model interpolatedModel =
773 modelInterpolator.interpolateModel( model, model.getProjectDirectory(), request, problems );
774 if ( interpolatedModel.getParent() != null )
775 {
776 StringSearchInterpolator ssi = new StringSearchInterpolator();
777 ssi.addValueSource( new MapBasedValueSource( request.getUserProperties() ) );
778
779 ssi.addValueSource( new MapBasedValueSource( model.getProperties() ) );
780
781 ssi.addValueSource( new MapBasedValueSource( request.getSystemProperties() ) );
782
783 try
784 {
785 String interpolated = ssi.interpolate( interpolatedModel.getParent().getVersion() );
786 interpolatedModel.getParent().setVersion( interpolated );
787 }
788 catch ( Exception e )
789 {
790 ModelProblemCollectorRequest mpcr =
791 new ModelProblemCollectorRequest( Severity.ERROR,
792 Version.BASE ).setMessage( "Failed to interpolate field: "
793 + interpolatedModel.getParent().getVersion()
794 + " on class: " ).setException( e );
795 problems.add( mpcr );
796 }
797
798
799 }
800 interpolatedModel.setPomFile( model.getPomFile() );
801
802
803 injectProfileActivations( model, originalActivations );
804
805 return interpolatedModel;
806 }
807
808 private ModelData readParent( Model childModel, ModelSource childSource, ModelBuildingRequest request,
809 DefaultModelProblemCollector problems )
810 throws ModelBuildingException
811 {
812 ModelData parentData;
813
814 Parent parent = childModel.getParent();
815
816 if ( parent != null )
817 {
818 String groupId = parent.getGroupId();
819 String artifactId = parent.getArtifactId();
820 String version = parent.getVersion();
821
822 parentData = getCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW );
823
824 if ( parentData == null )
825 {
826 parentData = readParentLocally( childModel, childSource, request, problems );
827
828 if ( parentData == null )
829 {
830 parentData = readParentExternally( childModel, request, problems );
831 }
832
833 putCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW, parentData );
834 }
835 else
836 {
837
838
839
840
841
842
843
844 File pomFile = parentData.getModel().getPomFile();
845 if ( pomFile != null )
846 {
847 ModelSource expectedParentSource = getParentPomFile( childModel, childSource );
848
849 if ( expectedParentSource == null || ( expectedParentSource instanceof ModelSource2
850 && !pomFile.toURI().equals( ( (ModelSource2) expectedParentSource ).getLocationURI() ) ) )
851 {
852 parentData = readParentExternally( childModel, request, problems );
853 }
854 }
855 }
856
857 Model parentModel = parentData.getModel();
858
859 if ( !"pom".equals( parentModel.getPackaging() ) )
860 {
861 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
862 .setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel )
863 + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"" )
864 .setLocation( parentModel.getLocation( "packaging" ) ) );
865 }
866 }
867 else
868 {
869 parentData = null;
870 }
871
872 return parentData;
873 }
874
875 private ModelData readParentLocally( Model childModel, ModelSource childSource, ModelBuildingRequest request,
876 DefaultModelProblemCollector problems )
877 throws ModelBuildingException
878 {
879 final Parent parent = childModel.getParent();
880 final ModelSource candidateSource;
881 final Model candidateModel;
882 final WorkspaceModelResolver resolver = request.getWorkspaceModelResolver();
883 if ( resolver == null )
884 {
885 candidateSource = getParentPomFile( childModel, childSource );
886
887 if ( candidateSource == null )
888 {
889 return null;
890 }
891
892 File pomFile = null;
893 if ( candidateSource instanceof FileModelSource )
894 {
895 pomFile = ( (FileModelSource) candidateSource ).getPomFile();
896 }
897
898 candidateModel = readModel( candidateSource, pomFile, request, problems );
899 }
900 else
901 {
902 try
903 {
904 candidateModel =
905 resolver.resolveRawModel( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
906 }
907 catch ( UnresolvableModelException e )
908 {
909 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
910 .setMessage( e.getMessage().toString() ).setLocation( parent.getLocation( "" ) ).setException( e ) );
911 throw problems.newModelBuildingException();
912 }
913 if ( candidateModel == null )
914 {
915 return null;
916 }
917 candidateSource = new FileModelSource( candidateModel.getPomFile() );
918 }
919
920
921
922
923
924
925
926 String groupId = candidateModel.getGroupId();
927 if ( groupId == null && candidateModel.getParent() != null )
928 {
929 groupId = candidateModel.getParent().getGroupId();
930 }
931 String artifactId = candidateModel.getArtifactId();
932 String version = candidateModel.getVersion();
933 if ( version == null && candidateModel.getParent() != null )
934 {
935 version = candidateModel.getParent().getVersion();
936 }
937
938 if ( groupId == null || !groupId.equals( parent.getGroupId() ) || artifactId == null
939 || !artifactId.equals( parent.getArtifactId() ) )
940 {
941 StringBuilder buffer = new StringBuilder( 256 );
942 buffer.append( "'parent.relativePath'" );
943 if ( childModel != problems.getRootModel() )
944 {
945 buffer.append( " of POM " ).append( ModelProblemUtils.toSourceHint( childModel ) );
946 }
947 buffer.append( " points at " ).append( groupId ).append( ':' ).append( artifactId );
948 buffer.append( " instead of " ).append( parent.getGroupId() ).append( ':' );
949 buffer.append( parent.getArtifactId() ).append( ", please verify your project structure" );
950
951 problems.setSource( childModel );
952 problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.BASE )
953 .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ) );
954 return null;
955 }
956 if ( version != null && parent.getVersion() != null && !version.equals( parent.getVersion() ) )
957 {
958 try
959 {
960 VersionRange parentRange = VersionRange.createFromVersionSpec( parent.getVersion() );
961 if ( !parentRange.hasRestrictions() )
962 {
963
964 return null;
965 }
966 if ( !parentRange.containsVersion( new DefaultArtifactVersion( version ) ) )
967 {
968
969 return null;
970 }
971
972
973 if ( childModel.getVersion() == null )
974 {
975
976 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
977 .setMessage( "Version must be a constant" ).setLocation( childModel.getLocation( "" ) ) );
978
979 }
980 else
981 {
982 if ( childModel.getVersion().contains( "${" ) )
983 {
984
985 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
986 .setMessage( "Version must be a constant" )
987 .setLocation( childModel.getLocation( "version" ) ) );
988
989 }
990 }
991
992
993 }
994 catch ( InvalidVersionSpecificationException e )
995 {
996
997 return null;
998 }
999 }
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010 ModelData parentData = new ModelData( candidateSource, candidateModel, groupId, artifactId, version );
1011
1012 return parentData;
1013 }
1014
1015 private ModelSource getParentPomFile( Model childModel, ModelSource source )
1016 {
1017 if ( !( source instanceof ModelSource2 ) )
1018 {
1019 return null;
1020 }
1021
1022 String parentPath = childModel.getParent().getRelativePath();
1023
1024 if ( parentPath == null || parentPath.length() <= 0 )
1025 {
1026 return null;
1027 }
1028
1029 return ( (ModelSource2) source ).getRelatedSource( parentPath );
1030 }
1031
1032 private ModelData readParentExternally( Model childModel, ModelBuildingRequest request,
1033 DefaultModelProblemCollector problems )
1034 throws ModelBuildingException
1035 {
1036 problems.setSource( childModel );
1037
1038 Parent parent = childModel.getParent().clone();
1039
1040 String groupId = parent.getGroupId();
1041 String artifactId = parent.getArtifactId();
1042 String version = parent.getVersion();
1043
1044 ModelResolver modelResolver = request.getModelResolver();
1045
1046 Validate.notNull( modelResolver, "request.modelResolver cannot be null (parent POM %s and POM %s)",
1047 ModelProblemUtils.toId( groupId, artifactId, version ), ModelProblemUtils.toSourceHint( childModel ) );
1048
1049 ModelSource modelSource;
1050 try
1051 {
1052 modelSource = modelResolver.resolveModel( parent );
1053 }
1054 catch ( UnresolvableModelException e )
1055 {
1056
1057 StringBuilder buffer = new StringBuilder( 256 );
1058 buffer.append( "Non-resolvable parent POM" );
1059 if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) )
1060 {
1061 buffer.append( ' ' ).append( ModelProblemUtils.toId( groupId, artifactId, version ) );
1062 }
1063 if ( childModel != problems.getRootModel() )
1064 {
1065 buffer.append( " for " ).append( ModelProblemUtils.toId( childModel ) );
1066 }
1067 buffer.append( ": " ).append( e.getMessage() );
1068 if ( childModel.getProjectDirectory() != null )
1069 {
1070 if ( parent.getRelativePath() == null || parent.getRelativePath().length() <= 0 )
1071 {
1072 buffer.append( " and 'parent.relativePath' points at no local POM" );
1073 }
1074 else
1075 {
1076 buffer.append( " and 'parent.relativePath' points at wrong local POM" );
1077 }
1078 }
1079
1080 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
1081 .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ).setException( e ) );
1082 throw problems.newModelBuildingException();
1083 }
1084
1085 ModelBuildingRequest lenientRequest = request;
1086 if ( request.getValidationLevel() > ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
1087 {
1088 lenientRequest = new FilterModelBuildingRequest( request )
1089 {
1090 @Override
1091 public int getValidationLevel()
1092 {
1093 return ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
1094 }
1095 };
1096 }
1097
1098 Model parentModel = readModel( modelSource, null, lenientRequest, problems );
1099
1100 if ( !parent.getVersion().equals( version ) )
1101 {
1102 if ( childModel.getVersion() == null )
1103 {
1104
1105 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
1106 .setMessage( "Version must be a constant" ).setLocation( childModel.getLocation( "" ) ) );
1107
1108 }
1109 else
1110 {
1111 if ( childModel.getVersion().contains( "${" ) )
1112 {
1113
1114 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
1115 .setMessage( "Version must be a constant" )
1116 .setLocation( childModel.getLocation( "version" ) ) );
1117
1118 }
1119 }
1120
1121
1122 }
1123
1124 ModelData parentData = new ModelData( modelSource, parentModel, parent.getGroupId(), parent.getArtifactId(),
1125 parent.getVersion() );
1126
1127 return parentData;
1128 }
1129
1130 private Model getSuperModel()
1131 {
1132 return superPomProvider.getSuperModel( "4.0.0" ).clone();
1133 }
1134
1135 @SuppressWarnings( "checkstyle:methodlength" )
1136 private void importDependencyManagement( Model model, ModelBuildingRequest request,
1137 DefaultModelProblemCollector problems, Collection<String> importIds )
1138 {
1139 DependencyManagement depMgmt = model.getDependencyManagement();
1140
1141 if ( depMgmt == null )
1142 {
1143 return;
1144 }
1145
1146 String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion();
1147
1148 importIds.add( importing );
1149
1150 final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver();
1151 final ModelResolver modelResolver = request.getModelResolver();
1152
1153 ModelBuildingRequest importRequest = null;
1154
1155 List<DependencyManagement> importMgmts = null;
1156
1157 for ( Iterator<Dependency> it = depMgmt.getDependencies().iterator(); it.hasNext(); )
1158 {
1159 Dependency dependency = it.next();
1160
1161 if ( !"pom".equals( dependency.getType() ) || !"import".equals( dependency.getScope() ) )
1162 {
1163 continue;
1164 }
1165
1166 it.remove();
1167
1168 String groupId = dependency.getGroupId();
1169 String artifactId = dependency.getArtifactId();
1170 String version = dependency.getVersion();
1171
1172 if ( groupId == null || groupId.length() <= 0 )
1173 {
1174 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
1175 .setMessage( "'dependencyManagement.dependencies.dependency.groupId' for "
1176 + dependency.getManagementKey() + " is missing." )
1177 .setLocation( dependency.getLocation( "" ) ) );
1178 continue;
1179 }
1180 if ( artifactId == null || artifactId.length() <= 0 )
1181 {
1182 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
1183 .setMessage( "'dependencyManagement.dependencies.dependency.artifactId' for "
1184 + dependency.getManagementKey() + " is missing." )
1185 .setLocation( dependency.getLocation( "" ) ) );
1186 continue;
1187 }
1188 if ( version == null || version.length() <= 0 )
1189 {
1190 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
1191 .setMessage( "'dependencyManagement.dependencies.dependency.version' for "
1192 + dependency.getManagementKey() + " is missing." )
1193 .setLocation( dependency.getLocation( "" ) ) );
1194 continue;
1195 }
1196
1197 String imported = groupId + ':' + artifactId + ':' + version;
1198
1199 if ( importIds.contains( imported ) )
1200 {
1201 String message = "The dependencies of type=pom and with scope=import form a cycle: ";
1202 for ( String modelId : importIds )
1203 {
1204 message += modelId + " -> ";
1205 }
1206 message += imported;
1207 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( message ) );
1208
1209 continue;
1210 }
1211
1212 DependencyManagement importMgmt = getCache( request.getModelCache(), groupId, artifactId, version,
1213 ModelCacheTag.IMPORT );
1214
1215 if ( importMgmt == null )
1216 {
1217 if ( workspaceResolver == null && modelResolver == null )
1218 {
1219 throw new NullPointerException( String.format(
1220 "request.workspaceModelResolver and request.modelResolver cannot be null"
1221 + " (parent POM %s and POM %s)",
1222 ModelProblemUtils.toId( groupId, artifactId, version ),
1223 ModelProblemUtils.toSourceHint( model ) ) );
1224 }
1225
1226 Model importModel = null;
1227 if ( workspaceResolver != null )
1228 {
1229 try
1230 {
1231 importModel = workspaceResolver.resolveEffectiveModel( groupId, artifactId, version );
1232 }
1233 catch ( UnresolvableModelException e )
1234 {
1235 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
1236 .setMessage( e.getMessage().toString() ).setException( e ) );
1237 continue;
1238 }
1239 }
1240
1241
1242 if ( importModel == null )
1243 {
1244 final ModelSource importSource;
1245 try
1246 {
1247 importSource = modelResolver.resolveModel( groupId, artifactId, version );
1248 }
1249 catch ( UnresolvableModelException e )
1250 {
1251 StringBuilder buffer = new StringBuilder( 256 );
1252 buffer.append( "Non-resolvable import POM" );
1253 if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) )
1254 {
1255 buffer.append( ' ' ).append( ModelProblemUtils.toId( groupId, artifactId, version ) );
1256 }
1257 buffer.append( ": " ).append( e.getMessage() );
1258
1259 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
1260 .setMessage( buffer.toString() ).setLocation( dependency.getLocation( "" ) )
1261 .setException( e ) );
1262 continue;
1263 }
1264
1265 if ( importRequest == null )
1266 {
1267 importRequest = new DefaultModelBuildingRequest();
1268 importRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
1269 importRequest.setModelCache( request.getModelCache() );
1270 importRequest.setSystemProperties( request.getSystemProperties() );
1271 importRequest.setUserProperties( request.getUserProperties() );
1272 importRequest.setLocationTracking( request.isLocationTracking() );
1273 }
1274
1275 importRequest.setModelSource( importSource );
1276 importRequest.setModelResolver( modelResolver.newCopy() );
1277
1278 final ModelBuildingResult importResult;
1279 try
1280 {
1281 importResult = build( importRequest );
1282 }
1283 catch ( ModelBuildingException e )
1284 {
1285 problems.addAll( e.getProblems() );
1286 continue;
1287 }
1288
1289 problems.addAll( importResult.getProblems() );
1290
1291 importModel = importResult.getEffectiveModel();
1292 }
1293
1294 importMgmt = importModel.getDependencyManagement();
1295
1296 if ( importMgmt == null )
1297 {
1298 importMgmt = new DependencyManagement();
1299 }
1300
1301 putCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt );
1302 }
1303
1304 if ( importMgmts == null )
1305 {
1306 importMgmts = new ArrayList<>();
1307 }
1308
1309 importMgmts.add( importMgmt );
1310 }
1311
1312 importIds.remove( importing );
1313
1314 dependencyManagementImporter.importManagement( model, importMgmts, request, problems );
1315 }
1316
1317 private <T> void putCache( ModelCache modelCache, String groupId, String artifactId, String version,
1318 ModelCacheTag<T> tag, T data )
1319 {
1320 if ( modelCache != null )
1321 {
1322 modelCache.put( groupId, artifactId, version, tag.getName(), tag.intoCache( data ) );
1323 }
1324 }
1325
1326 private <T> T getCache( ModelCache modelCache, String groupId, String artifactId, String version,
1327 ModelCacheTag<T> tag )
1328 {
1329 if ( modelCache != null )
1330 {
1331 Object data = modelCache.get( groupId, artifactId, version, tag.getName() );
1332 if ( data != null )
1333 {
1334 return tag.fromCache( tag.getType().cast( data ) );
1335 }
1336 }
1337 return null;
1338 }
1339
1340 private void fireEvent( Model model, ModelBuildingRequest request, ModelProblemCollector problems,
1341 ModelBuildingEventCatapult catapult )
1342 throws ModelBuildingException
1343 {
1344 ModelBuildingListener listener = request.getModelBuildingListener();
1345
1346 if ( listener != null )
1347 {
1348 ModelBuildingEvent event = new DefaultModelBuildingEvent( model, request, problems );
1349
1350 catapult.fire( listener, event );
1351 }
1352 }
1353
1354 private boolean containsCoordinates( String message, String groupId, String artifactId, String version )
1355 {
1356 return message != null && ( groupId == null || message.contains( groupId ) )
1357 && ( artifactId == null || message.contains( artifactId ) )
1358 && ( version == null || message.contains( version ) );
1359 }
1360
1361 protected boolean hasModelErrors( ModelProblemCollectorExt problems )
1362 {
1363 if ( problems instanceof DefaultModelProblemCollector )
1364 {
1365 return ( (DefaultModelProblemCollector) problems ).hasErrors();
1366 }
1367 else
1368 {
1369
1370
1371 throw new IllegalStateException();
1372 }
1373 }
1374
1375 protected boolean hasFatalErrors( ModelProblemCollectorExt problems )
1376 {
1377 if ( problems instanceof DefaultModelProblemCollector )
1378 {
1379 return ( (DefaultModelProblemCollector) problems ).hasFatalErrors();
1380 }
1381 else
1382 {
1383
1384
1385 throw new IllegalStateException();
1386 }
1387 }
1388
1389 }