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