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