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