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