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 depMngmntImporter )
199 {
200 this.dependencyManagementImporter = depMngmntImporter;
201 return this;
202 }
203
204 public DefaultModelBuilder setDependencyManagementInjector( DependencyManagementInjector depMngmntInjector )
205 {
206 this.dependencyManagementInjector = depMngmntInjector;
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 mngt = build.getPluginManagement();
687 if ( mngt != null )
688 {
689 for ( Plugin plugin : mngt.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 catch ( InvalidVersionSpecificationException e )
943 {
944
945 return null;
946 }
947 }
948
949
950
951
952
953
954
955
956
957
958 ModelData parentData = new ModelData( candidateSource, candidateModel, groupId, artifactId, version );
959
960 return parentData;
961 }
962
963 private ModelSource getParentPomFile( Model childModel, ModelSource source )
964 {
965 if ( !( source instanceof ModelSource2 ) )
966 {
967 return null;
968 }
969
970 String parentPath = childModel.getParent().getRelativePath();
971
972 if ( parentPath == null || parentPath.length() <= 0 )
973 {
974 return null;
975 }
976
977 return ( (ModelSource2) source ).getRelatedSource( parentPath );
978 }
979
980 private ModelData readParentExternally( Model childModel, ModelBuildingRequest request,
981 DefaultModelProblemCollector problems )
982 throws ModelBuildingException
983 {
984 problems.setSource( childModel );
985
986 Parent parent = childModel.getParent().clone();
987
988 String groupId = parent.getGroupId();
989 String artifactId = parent.getArtifactId();
990 String version = parent.getVersion();
991
992 ModelResolver modelResolver = request.getModelResolver();
993
994 Validate.notNull( modelResolver, "request.modelResolver cannot be null (parent POM %s and POM %s)",
995 ModelProblemUtils.toId( groupId, artifactId, version ), ModelProblemUtils.toSourceHint( childModel ) );
996
997 ModelSource modelSource;
998 try
999 {
1000 modelSource = modelResolver.resolveModel( parent );
1001 }
1002 catch ( UnresolvableModelException e )
1003 {
1004 StringBuilder buffer = new StringBuilder( 256 );
1005 buffer.append( "Non-resolvable parent POM" );
1006 if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) )
1007 {
1008 buffer.append( " " ).append( ModelProblemUtils.toId( groupId, artifactId, version ) );
1009 }
1010 if ( childModel != problems.getRootModel() )
1011 {
1012 buffer.append( " for " ).append( ModelProblemUtils.toId( childModel ) );
1013 }
1014 buffer.append( ": " ).append( e.getMessage() );
1015 if ( childModel.getProjectDirectory() != null )
1016 {
1017 if ( parent.getRelativePath() == null || parent.getRelativePath().length() <= 0 )
1018 {
1019 buffer.append( " and 'parent.relativePath' points at no local POM" );
1020 }
1021 else
1022 {
1023 buffer.append( " and 'parent.relativePath' points at wrong local POM" );
1024 }
1025 }
1026
1027 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
1028 .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ).setException( e ) );
1029 throw problems.newModelBuildingException();
1030 }
1031
1032 ModelBuildingRequest lenientRequest = request;
1033 if ( request.getValidationLevel() > ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
1034 {
1035 lenientRequest = new FilterModelBuildingRequest( request )
1036 {
1037 @Override
1038 public int getValidationLevel()
1039 {
1040 return ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
1041 }
1042 };
1043 }
1044
1045 Model parentModel = readModel( modelSource, null, lenientRequest, problems );
1046
1047 if ( !parent.getVersion().equals( version ) )
1048 {
1049 if ( childModel.getVersion() == null )
1050 {
1051 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
1052 .setMessage( "Version must be a constant" ).setLocation( childModel.getLocation( "" ) ) );
1053
1054 }
1055 else
1056 {
1057 if ( childModel.getVersion()
1058 .contains( "${" ) )
1059 {
1060 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
1061 .setMessage( "Version must be a constant" )
1062 .setLocation( childModel.getLocation( "version" ) ) );
1063
1064 }
1065 }
1066
1067
1068 }
1069
1070 ModelData parentData = new ModelData( modelSource, parentModel, parent.getGroupId(), parent.getArtifactId(),
1071 parent.getVersion() );
1072
1073 return parentData;
1074 }
1075
1076 private Model getSuperModel()
1077 {
1078 return superPomProvider.getSuperModel( "4.0.0" ).clone();
1079 }
1080
1081 private void importDependencyManagement( Model model, ModelBuildingRequest request,
1082 DefaultModelProblemCollector problems, Collection<String> importIds )
1083 {
1084 DependencyManagement depMngt = model.getDependencyManagement();
1085
1086 if ( depMngt == null )
1087 {
1088 return;
1089 }
1090
1091 String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion();
1092
1093 importIds.add( importing );
1094
1095 final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver();
1096 final ModelResolver modelResolver = request.getModelResolver();
1097
1098 ModelBuildingRequest importRequest = null;
1099
1100 List<DependencyManagement> importMngts = null;
1101
1102 for ( Iterator<Dependency> it = depMngt.getDependencies().iterator(); it.hasNext(); )
1103 {
1104 Dependency dependency = it.next();
1105
1106 if ( !"pom".equals( dependency.getType() ) || !"import".equals( dependency.getScope() ) )
1107 {
1108 continue;
1109 }
1110
1111 it.remove();
1112
1113 String groupId = dependency.getGroupId();
1114 String artifactId = dependency.getArtifactId();
1115 String version = dependency.getVersion();
1116
1117 if ( groupId == null || groupId.length() <= 0 )
1118 {
1119 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
1120 .setMessage( "'dependencyManagement.dependencies.dependency.groupId' for "
1121 + dependency.getManagementKey() + " is missing." )
1122 .setLocation( dependency.getLocation( "" ) ) );
1123 continue;
1124 }
1125 if ( artifactId == null || artifactId.length() <= 0 )
1126 {
1127 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
1128 .setMessage( "'dependencyManagement.dependencies.dependency.artifactId' for "
1129 + dependency.getManagementKey() + " is missing." )
1130 .setLocation( dependency.getLocation( "" ) ) );
1131 continue;
1132 }
1133 if ( version == null || version.length() <= 0 )
1134 {
1135 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
1136 .setMessage( "'dependencyManagement.dependencies.dependency.version' for "
1137 + dependency.getManagementKey() + " is missing." )
1138 .setLocation( dependency.getLocation( "" ) ) );
1139 continue;
1140 }
1141
1142 String imported = groupId + ':' + artifactId + ':' + version;
1143
1144 if ( importIds.contains( imported ) )
1145 {
1146 String message = "The dependencies of type=pom and with scope=import form a cycle: ";
1147 for ( String modelId : importIds )
1148 {
1149 message += modelId + " -> ";
1150 }
1151 message += imported;
1152 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( message ) );
1153
1154 continue;
1155 }
1156
1157 DependencyManagement importMngt = getCache( request.getModelCache(), groupId, artifactId, version,
1158 ModelCacheTag.IMPORT );
1159
1160 if ( importMngt == null )
1161 {
1162 if ( workspaceResolver == null && modelResolver == null )
1163 {
1164 throw new NullPointerException( String.format(
1165 "request.workspaceModelResolver and request.modelResolver cannot be null"
1166 + " (parent POM %s and POM %s)",
1167 ModelProblemUtils.toId( groupId, artifactId, version ),
1168 ModelProblemUtils.toSourceHint( model ) ) );
1169 }
1170
1171 Model importModel = null;
1172 if ( workspaceResolver != null )
1173 {
1174 try
1175 {
1176 importModel = workspaceResolver.resolveEffectiveModel( groupId, artifactId, version );
1177 }
1178 catch ( UnresolvableModelException e )
1179 {
1180 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
1181 .setMessage( e.getMessage().toString() ).setException( e ) );
1182 continue;
1183 }
1184 }
1185
1186
1187 if ( importModel == null )
1188 {
1189 final ModelSource importSource;
1190 try
1191 {
1192 importSource = modelResolver.resolveModel( groupId, artifactId, version );
1193 }
1194 catch ( UnresolvableModelException e )
1195 {
1196 StringBuilder buffer = new StringBuilder( 256 );
1197 buffer.append( "Non-resolvable import POM" );
1198 if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) )
1199 {
1200 buffer.append( " " ).append( ModelProblemUtils.toId( groupId, artifactId, version ) );
1201 }
1202 buffer.append( ": " ).append( e.getMessage() );
1203
1204 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
1205 .setMessage( buffer.toString() ).setLocation( dependency.getLocation( "" ) )
1206 .setException( e ) );
1207 continue;
1208 }
1209
1210 if ( importRequest == null )
1211 {
1212 importRequest = new DefaultModelBuildingRequest();
1213 importRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
1214 importRequest.setModelCache( request.getModelCache() );
1215 importRequest.setSystemProperties( request.getSystemProperties() );
1216 importRequest.setUserProperties( request.getUserProperties() );
1217 importRequest.setLocationTracking( request.isLocationTracking() );
1218 }
1219
1220 importRequest.setModelSource( importSource );
1221 importRequest.setModelResolver( modelResolver.newCopy() );
1222
1223 final ModelBuildingResult importResult;
1224 try
1225 {
1226 importResult = build( importRequest );
1227 }
1228 catch ( ModelBuildingException e )
1229 {
1230 problems.addAll( e.getProblems() );
1231 continue;
1232 }
1233
1234 problems.addAll( importResult.getProblems() );
1235
1236 importModel = importResult.getEffectiveModel();
1237 }
1238
1239 importMngt = importModel.getDependencyManagement();
1240
1241 if ( importMngt == null )
1242 {
1243 importMngt = new DependencyManagement();
1244 }
1245
1246 putCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMngt );
1247 }
1248
1249 if ( importMngts == null )
1250 {
1251 importMngts = new ArrayList<>();
1252 }
1253
1254 importMngts.add( importMngt );
1255 }
1256
1257 importIds.remove( importing );
1258
1259 dependencyManagementImporter.importManagement( model, importMngts, request, problems );
1260 }
1261
1262 private <T> void putCache( ModelCache modelCache, String groupId, String artifactId, String version,
1263 ModelCacheTag<T> tag, T data )
1264 {
1265 if ( modelCache != null )
1266 {
1267 modelCache.put( groupId, artifactId, version, tag.getName(), tag.intoCache( data ) );
1268 }
1269 }
1270
1271 private <T> T getCache( ModelCache modelCache, String groupId, String artifactId, String version,
1272 ModelCacheTag<T> tag )
1273 {
1274 if ( modelCache != null )
1275 {
1276 Object data = modelCache.get( groupId, artifactId, version, tag.getName() );
1277 if ( data != null )
1278 {
1279 return tag.fromCache( tag.getType().cast( data ) );
1280 }
1281 }
1282 return null;
1283 }
1284
1285 private void fireEvent( Model model, ModelBuildingRequest request, ModelProblemCollector problems,
1286 ModelBuildingEventCatapult catapult )
1287 throws ModelBuildingException
1288 {
1289 ModelBuildingListener listener = request.getModelBuildingListener();
1290
1291 if ( listener != null )
1292 {
1293 ModelBuildingEvent event = new DefaultModelBuildingEvent( model, request, problems );
1294
1295 catapult.fire( listener, event );
1296 }
1297 }
1298
1299 private boolean containsCoordinates( String message, String groupId, String artifactId, String version )
1300 {
1301 return message != null && ( groupId == null || message.contains( groupId ) )
1302 && ( artifactId == null || message.contains( artifactId ) )
1303 && ( version == null || message.contains( version ) );
1304 }
1305
1306 protected boolean hasModelErrors( ModelProblemCollectorExt problems )
1307 {
1308 if ( problems instanceof DefaultModelProblemCollector )
1309 {
1310 return ( (DefaultModelProblemCollector) problems ).hasErrors();
1311 }
1312 else
1313 {
1314
1315
1316 throw new IllegalStateException();
1317 }
1318 }
1319
1320 protected boolean hasFatalErrors( ModelProblemCollectorExt problems )
1321 {
1322 if ( problems instanceof DefaultModelProblemCollector )
1323 {
1324 return ( (DefaultModelProblemCollector) problems ).hasFatalErrors();
1325 }
1326 else
1327 {
1328
1329
1330 throw new IllegalStateException();
1331 }
1332 }
1333
1334 }