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