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