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