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