001package org.apache.maven.model.building; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.io.IOException; 024import java.util.ArrayList; 025import java.util.Collection; 026import java.util.Iterator; 027import java.util.LinkedHashSet; 028import java.util.List; 029import java.util.Map; 030import java.util.HashMap; 031import java.util.Properties; 032 033import org.apache.maven.model.Build; 034import org.apache.maven.model.Dependency; 035import org.apache.maven.model.DependencyManagement; 036import org.apache.maven.model.InputLocation; 037import org.apache.maven.model.InputSource; 038import org.apache.maven.model.Model; 039import org.apache.maven.model.Parent; 040import org.apache.maven.model.Plugin; 041import org.apache.maven.model.PluginManagement; 042import org.apache.maven.model.Profile; 043import org.apache.maven.model.Repository; 044import org.apache.maven.model.building.ModelProblem.Severity; 045import org.apache.maven.model.building.ModelProblem.Version; 046import org.apache.maven.model.composition.DependencyManagementImporter; 047import org.apache.maven.model.inheritance.InheritanceAssembler; 048import org.apache.maven.model.interpolation.ModelInterpolator; 049import org.apache.maven.model.io.ModelParseException; 050import org.apache.maven.model.management.DependencyManagementInjector; 051import org.apache.maven.model.management.PluginManagementInjector; 052import org.apache.maven.model.normalization.ModelNormalizer; 053import org.apache.maven.model.path.ModelPathTranslator; 054import org.apache.maven.model.path.ModelUrlNormalizer; 055import org.apache.maven.model.plugin.LifecycleBindingsInjector; 056import org.apache.maven.model.plugin.PluginConfigurationExpander; 057import org.apache.maven.model.plugin.ReportConfigurationExpander; 058import org.apache.maven.model.plugin.ReportingConverter; 059import org.apache.maven.model.profile.DefaultProfileActivationContext; 060import org.apache.maven.model.profile.ProfileInjector; 061import org.apache.maven.model.profile.ProfileSelector; 062import org.apache.maven.model.resolution.InvalidRepositoryException; 063import org.apache.maven.model.resolution.ModelResolver; 064import org.apache.maven.model.resolution.UnresolvableModelException; 065import org.apache.maven.model.superpom.SuperPomProvider; 066import org.apache.maven.model.validation.ModelValidator; 067import org.codehaus.plexus.component.annotations.Component; 068import org.codehaus.plexus.component.annotations.Requirement; 069 070/** 071 * @author Benjamin Bentmann 072 */ 073@Component( role = ModelBuilder.class ) 074public class DefaultModelBuilder 075 implements ModelBuilder 076{ 077 @Requirement 078 private ModelProcessor modelProcessor; 079 080 @Requirement 081 private ModelValidator modelValidator; 082 083 @Requirement 084 private ModelNormalizer modelNormalizer; 085 086 @Requirement 087 private ModelInterpolator modelInterpolator; 088 089 @Requirement 090 private ModelPathTranslator modelPathTranslator; 091 092 @Requirement 093 private ModelUrlNormalizer modelUrlNormalizer; 094 095 @Requirement 096 private SuperPomProvider superPomProvider; 097 098 @Requirement 099 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( request.getModelSource(), inputModel ); 261 ModelData superData = new ModelData( null, 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 profileActivationContext.setProjectProperties( tmpModel.getProperties() ); 282 283 List<Profile> activePomProfiles = 284 profileSelector.getActiveProfiles( rawModel.getProfiles(), profileActivationContext, problems ); 285 currentData.setActiveProfiles( activePomProfiles ); 286 287 for ( Profile activeProfile : activePomProfiles ) 288 { 289 profileInjector.injectProfile( tmpModel, activeProfile, request, problems ); 290 } 291 292 if ( currentData == resultData ) 293 { 294 for ( Profile activeProfile : activeExternalProfiles ) 295 { 296 profileInjector.injectProfile( tmpModel, activeProfile, request, problems ); 297 } 298 } 299 300 if ( currentData == superData ) 301 { 302 break; 303 } 304 305 configureResolver( request.getModelResolver(), tmpModel, problems ); 306 307 currentData = readParent( tmpModel, currentData.getSource(), request, problems ); 308 309 if ( currentData == null ) 310 { 311 currentData = superData; 312 } 313 else if ( !parentIds.add( currentData.getId() ) ) 314 { 315 String message = "The parents form a cycle: "; 316 for ( String modelId : parentIds ) 317 { 318 message += modelId + " -> "; 319 } 320 message += currentData.getId(); 321 322 problems.add( new ModelProblemCollectorRequest( ModelProblem.Severity.FATAL, ModelProblem.Version.BASE ).setMessage( message ) ); 323 throw problems.newModelBuildingException(); 324 } 325 } 326 327 problems.setSource( inputModel ); 328 checkPluginVersions( lineage, request, problems ); 329 330 assembleInheritance( lineage, request, problems ); 331 332 Model resultModel = resultData.getModel(); 333 334 problems.setSource( resultModel ); 335 problems.setRootModel( resultModel ); 336 337 resultModel = interpolateModel( resultModel, request, problems ); 338 resultData.setModel( resultModel ); 339 340 modelUrlNormalizer.normalize( resultModel, request ); 341 342 resultData.setGroupId( resultModel.getGroupId() ); 343 resultData.setArtifactId( resultModel.getArtifactId() ); 344 resultData.setVersion( resultModel.getVersion() ); 345 346 result.setEffectiveModel( resultModel ); 347 348 for ( ModelData currentData : lineage ) 349 { 350 String modelId = ( currentData != superData ) ? currentData.getId() : ""; 351 352 result.addModelId( modelId ); 353 result.setActivePomProfiles( modelId, currentData.getActiveProfiles() ); 354 result.setRawModel( modelId, currentData.getRawModel() ); 355 } 356 357 if ( !request.isTwoPhaseBuilding() ) 358 { 359 build( request, result ); 360 } 361 362 return result; 363 } 364 365 public ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result ) 366 throws ModelBuildingException 367 { 368 return build( request, result, new LinkedHashSet<String>() ); 369 } 370 371 private ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result, 372 Collection<String> imports ) 373 throws ModelBuildingException 374 { 375 Model resultModel = result.getEffectiveModel(); 376 377 DefaultModelProblemCollector problems = new DefaultModelProblemCollector( result ); 378 problems.setSource( resultModel ); 379 problems.setRootModel( resultModel ); 380 381 modelPathTranslator.alignToBaseDirectory( resultModel, resultModel.getProjectDirectory(), request ); 382 383 pluginManagementInjector.injectManagement( resultModel, request, problems ); 384 385 fireEvent( resultModel, request, problems, ModelBuildingEventCatapult.BUILD_EXTENSIONS_ASSEMBLED ); 386 387 if ( request.isProcessPlugins() ) 388 { 389 if ( lifecycleBindingsInjector == null ) 390 { 391 throw new IllegalStateException( "lifecycle bindings injector is missing" ); 392 } 393 394 lifecycleBindingsInjector.injectLifecycleBindings( resultModel, request, problems ); 395 } 396 397 importDependencyManagement( resultModel, request, problems, imports ); 398 399 dependencyManagementInjector.injectManagement( resultModel, request, problems ); 400 401 modelNormalizer.injectDefaultValues( resultModel, request, problems ); 402 403 if ( request.isProcessPlugins() ) 404 { 405 reportConfigurationExpander.expandPluginConfiguration( resultModel, request, problems ); 406 407 reportingConverter.convertReporting( resultModel, request, problems ); 408 409 pluginConfigurationExpander.expandPluginConfiguration( resultModel, request, problems ); 410 } 411 412 modelValidator.validateEffectiveModel( resultModel, request, problems ); 413 414 if ( hasModelErrors( problems ) ) 415 { 416 throw problems.newModelBuildingException(); 417 } 418 419 return result; 420 } 421 422 private Model readModel( ModelSource modelSource, File pomFile, ModelBuildingRequest request, 423 DefaultModelProblemCollector problems ) 424 throws ModelBuildingException 425 { 426 Model model; 427 428 if ( modelSource == null ) 429 { 430 if ( pomFile != null ) 431 { 432 modelSource = new FileModelSource( pomFile ); 433 } 434 else 435 { 436 throw new IllegalArgumentException( "neither model source nor input file are specified" ); 437 } 438 } 439 440 problems.setSource( modelSource.getLocation() ); 441 try 442 { 443 boolean strict = request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0; 444 InputSource source = request.isLocationTracking() ? new InputSource() : null; 445 446 Map<String, Object> options = new HashMap<String, Object>(); 447 options.put( ModelProcessor.IS_STRICT, strict ); 448 options.put( ModelProcessor.INPUT_SOURCE, source ); 449 options.put( ModelProcessor.SOURCE, modelSource ); 450 451 try 452 { 453 model = modelProcessor.read( modelSource.getInputStream(), options ); 454 } 455 catch ( ModelParseException e ) 456 { 457 if ( !strict ) 458 { 459 throw e; 460 } 461 462 options.put( ModelProcessor.IS_STRICT, Boolean.FALSE ); 463 464 try 465 { 466 model = modelProcessor.read( modelSource.getInputStream(), options ); 467 } 468 catch ( ModelParseException ne ) 469 { 470 // still unreadable even in non-strict mode, rethrow original error 471 throw e; 472 } 473 474 if ( pomFile != null ) 475 { 476 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.V20 ) 477 .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() ) 478 .setException( e ) ); 479 } 480 else 481 { 482 problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 ) 483 .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() ) 484 .setException( e ) ); 485 } 486 } 487 488 if ( source != null ) 489 { 490 source.setModelId( ModelProblemUtils.toId( model ) ); 491 source.setLocation( modelSource.getLocation() ); 492 } 493 } 494 catch ( ModelParseException e ) 495 { 496 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) 497 .setMessage( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage() ) 498 .setException( e ) ); 499 throw problems.newModelBuildingException(); 500 } 501 catch ( IOException e ) 502 { 503 String msg = e.getMessage(); 504 if ( msg == null || msg.length() <= 0 ) 505 { 506 // NOTE: There's java.nio.charset.MalformedInputException and sun.io.MalformedInputException 507 if ( e.getClass().getName().endsWith( "MalformedInputException" ) ) 508 { 509 msg = "Some input bytes do not match the file encoding."; 510 } 511 else 512 { 513 msg = e.getClass().getSimpleName(); 514 } 515 } 516 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) 517 .setMessage( "Non-readable POM " + modelSource.getLocation() + ": " + msg ) 518 .setException( e ) ); 519 throw problems.newModelBuildingException(); 520 } 521 522 model.setPomFile( pomFile ); 523 524 problems.setSource( model ); 525 modelValidator.validateRawModel( model, request, problems ); 526 527 if ( hasFatalErrors( problems ) ) 528 { 529 throw problems.newModelBuildingException(); 530 } 531 532 return model; 533 } 534 535 private DefaultProfileActivationContext getProfileActivationContext( ModelBuildingRequest request ) 536 { 537 DefaultProfileActivationContext context = new DefaultProfileActivationContext(); 538 539 context.setActiveProfileIds( request.getActiveProfileIds() ); 540 context.setInactiveProfileIds( request.getInactiveProfileIds() ); 541 context.setSystemProperties( request.getSystemProperties() ); 542 context.setUserProperties( request.getUserProperties() ); 543 context.setProjectDirectory( ( request.getPomFile() != null ) ? request.getPomFile().getParentFile() : null ); 544 545 return context; 546 } 547 548 private void configureResolver( ModelResolver modelResolver, Model model, DefaultModelProblemCollector problems ) 549 { 550 if ( modelResolver == null ) 551 { 552 return; 553 } 554 555 problems.setSource( model ); 556 557 List<Repository> repositories = model.getRepositories(); 558 559 for ( Repository repository : repositories ) 560 { 561 try 562 { 563 modelResolver.addRepository( repository ); 564 } 565 catch ( InvalidRepositoryException e ) 566 { 567 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) 568 .setMessage( "Invalid repository " + repository.getId() + ": " + e.getMessage() ) 569 .setLocation( repository.getLocation( "" ) ) 570 .setException( e ) ); 571 } 572 } 573 } 574 575 private void checkPluginVersions( List<ModelData> lineage, ModelBuildingRequest request, 576 ModelProblemCollector problems ) 577 { 578 if ( request.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 ) 579 { 580 return; 581 } 582 583 Map<String, Plugin> plugins = new HashMap<String, Plugin>(); 584 Map<String, String> versions = new HashMap<String, String>(); 585 Map<String, String> managedVersions = new HashMap<String, String>(); 586 587 for ( int i = lineage.size() - 1; i >= 0; i-- ) 588 { 589 Model model = lineage.get( i ).getModel(); 590 Build build = model.getBuild(); 591 if ( build != null ) 592 { 593 for ( Plugin plugin : build.getPlugins() ) 594 { 595 String key = plugin.getKey(); 596 if ( versions.get( key ) == null ) 597 { 598 versions.put( key, plugin.getVersion() ); 599 plugins.put( key, plugin ); 600 } 601 } 602 PluginManagement mngt = build.getPluginManagement(); 603 if ( mngt != null ) 604 { 605 for ( Plugin plugin : mngt.getPlugins() ) 606 { 607 String key = plugin.getKey(); 608 if ( managedVersions.get( key ) == null ) 609 { 610 managedVersions.put( key, plugin.getVersion() ); 611 } 612 } 613 } 614 } 615 } 616 617 for ( String key : versions.keySet() ) 618 { 619 if ( versions.get( key ) == null && managedVersions.get( key ) == null ) 620 { 621 InputLocation location = plugins.get( key ).getLocation( "" ); 622 problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 ) 623 .setMessage( "'build.plugins.plugin.version' for " + key + " is missing." ) 624 .setLocation( location ) ); 625 } 626 } 627 } 628 629 private void assembleInheritance( List<ModelData> lineage, ModelBuildingRequest request, 630 ModelProblemCollector problems ) 631 { 632 for ( int i = lineage.size() - 2; i >= 0; i-- ) 633 { 634 Model parent = lineage.get( i + 1 ).getModel(); 635 Model child = lineage.get( i ).getModel(); 636 inheritanceAssembler.assembleModelInheritance( child, parent, request, problems ); 637 } 638 } 639 640 private Model interpolateModel( Model model, ModelBuildingRequest request, ModelProblemCollector problems ) 641 { 642 Model result = modelInterpolator.interpolateModel( model, model.getProjectDirectory(), request, problems ); 643 result.setPomFile( model.getPomFile() ); 644 return result; 645 } 646 647 private ModelData readParent( Model childModel, ModelSource childSource, ModelBuildingRequest request, 648 DefaultModelProblemCollector problems ) 649 throws ModelBuildingException 650 { 651 ModelData parentData; 652 653 Parent parent = childModel.getParent(); 654 655 if ( parent != null ) 656 { 657 String groupId = parent.getGroupId(); 658 String artifactId = parent.getArtifactId(); 659 String version = parent.getVersion(); 660 661 parentData = getCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW ); 662 663 if ( parentData == null ) 664 { 665 parentData = readParentLocally( childModel, childSource, request, problems ); 666 667 if ( parentData == null ) 668 { 669 parentData = readParentExternally( childModel, request, problems ); 670 } 671 672 putCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.RAW, parentData ); 673 } 674 else 675 { 676 /* 677 * NOTE: This is a sanity check of the cache hit. If the cached parent POM was locally resolved, the 678 * child's <relativePath> should point at that parent, too. If it doesn't, we ignore the cache and 679 * resolve externally, to mimic the behavior if the cache didn't exist in the first place. Otherwise, 680 * the cache would obscure a bad POM. 681 */ 682 683 File pomFile = parentData.getModel().getPomFile(); 684 if ( pomFile != null ) 685 { 686 ModelSource expectedParentSource = getParentPomFile( childModel, childSource ); 687 688 if ( expectedParentSource instanceof ModelSource2 689 && !pomFile.toURI().equals( ( (ModelSource2) expectedParentSource ).getLocationURI() ) ) 690 { 691 parentData = readParentExternally( childModel, request, problems ); 692 } 693 } 694 } 695 696 Model parentModel = parentData.getModel(); 697 698 if ( !"pom".equals( parentModel.getPackaging() ) ) 699 { 700 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) 701 .setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel ) 702 + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"" ) 703 .setLocation( parentModel.getLocation( "packaging" ) ) ); 704 } 705 } 706 else 707 { 708 parentData = null; 709 } 710 711 return parentData; 712 } 713 714 private ModelData readParentLocally( Model childModel, ModelSource childSource, ModelBuildingRequest request, 715 DefaultModelProblemCollector problems ) 716 throws ModelBuildingException 717 { 718 ModelSource candidateSource = getParentPomFile( childModel, childSource ); 719 720 if ( candidateSource == null ) 721 { 722 return null; 723 } 724 725 File pomFile = null; 726 if ( candidateSource instanceof FileModelSource ) 727 { 728 pomFile = ( (FileModelSource) candidateSource ).getPomFile(); 729 } 730 731 Model candidateModel = readModel( candidateSource, pomFile, request, problems ); 732 733 String groupId = candidateModel.getGroupId(); 734 if ( groupId == null && candidateModel.getParent() != null ) 735 { 736 groupId = candidateModel.getParent().getGroupId(); 737 } 738 String artifactId = candidateModel.getArtifactId(); 739 String version = candidateModel.getVersion(); 740 if ( version == null && candidateModel.getParent() != null ) 741 { 742 version = candidateModel.getParent().getVersion(); 743 } 744 745 Parent parent = childModel.getParent(); 746 747 if ( groupId == null || !groupId.equals( parent.getGroupId() ) || artifactId == null 748 || !artifactId.equals( parent.getArtifactId() ) ) 749 { 750 StringBuilder buffer = new StringBuilder( 256 ); 751 buffer.append( "'parent.relativePath'" ); 752 if ( childModel != problems.getRootModel() ) 753 { 754 buffer.append( " of POM " ).append( ModelProblemUtils.toSourceHint( childModel ) ); 755 } 756 buffer.append( " points at " ).append( groupId ).append( ":" ).append( artifactId ); 757 buffer.append( " instead of " ).append( parent.getGroupId() ).append( ":" ).append( parent.getArtifactId() ); 758 buffer.append( ", please verify your project structure" ); 759 760 problems.setSource( childModel ); 761 problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.BASE ) 762 .setMessage( buffer.toString() ) 763 .setLocation( parent.getLocation( "" ) ) ); 764 return null; 765 } 766 if ( version == null || !version.equals( parent.getVersion() ) ) 767 { 768 return null; 769 } 770 771 ModelData parentData = new ModelData( candidateSource, candidateModel, groupId, artifactId, version ); 772 773 return parentData; 774 } 775 776 private ModelSource getParentPomFile( Model childModel, ModelSource source ) 777 { 778 if ( !( source instanceof ModelSource2 ) ) 779 { 780 return null; 781 } 782 783 String parentPath = childModel.getParent().getRelativePath(); 784 785 if ( parentPath == null || parentPath.length() <= 0 ) 786 { 787 return null; 788 } 789 790 return ( (ModelSource2) source ).getRelatedSource( parentPath ); 791 } 792 793 private ModelData readParentExternally( Model childModel, ModelBuildingRequest request, 794 DefaultModelProblemCollector problems ) 795 throws ModelBuildingException 796 { 797 problems.setSource( childModel ); 798 799 Parent parent = childModel.getParent(); 800 801 String groupId = parent.getGroupId(); 802 String artifactId = parent.getArtifactId(); 803 String version = parent.getVersion(); 804 805 ModelResolver modelResolver = request.getModelResolver(); 806 807 if ( modelResolver == null ) 808 { 809 throw new IllegalArgumentException( "no model resolver provided, cannot resolve parent POM " 810 + ModelProblemUtils.toId( groupId, artifactId, version ) + " for POM " 811 + ModelProblemUtils.toSourceHint( childModel ) ); 812 } 813 814 ModelSource modelSource; 815 try 816 { 817 modelSource = modelResolver.resolveModel( groupId, artifactId, version ); 818 } 819 catch ( UnresolvableModelException e ) 820 { 821 StringBuilder buffer = new StringBuilder( 256 ); 822 buffer.append( "Non-resolvable parent POM" ); 823 if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) ) 824 { 825 buffer.append( " " ).append( ModelProblemUtils.toId( groupId, artifactId, version ) ); 826 } 827 if ( childModel != problems.getRootModel() ) 828 { 829 buffer.append( " for " ).append( ModelProblemUtils.toId( childModel ) ); 830 } 831 buffer.append( ": " ).append( e.getMessage() ); 832 if ( childModel.getProjectDirectory() != null ) 833 { 834 if ( parent.getRelativePath() == null || parent.getRelativePath().length() <= 0 ) 835 { 836 buffer.append( " and 'parent.relativePath' points at no local POM" ); 837 } 838 else 839 { 840 buffer.append( " and 'parent.relativePath' points at wrong local POM" ); 841 } 842 } 843 844 problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) 845 .setMessage( buffer.toString() ) 846 .setLocation( parent.getLocation( "" ) ) 847 .setException( e ) ); 848 throw problems.newModelBuildingException(); 849 } 850 851 ModelBuildingRequest lenientRequest = request; 852 if ( request.getValidationLevel() > ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 ) 853 { 854 lenientRequest = new FilterModelBuildingRequest( request ) 855 { 856 @Override 857 public int getValidationLevel() 858 { 859 return ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0; 860 } 861 }; 862 } 863 864 Model parentModel = readModel( modelSource, null, lenientRequest, problems ); 865 866 ModelData parentData = new ModelData( modelSource, parentModel, groupId, artifactId, version ); 867 868 return parentData; 869 } 870 871 private Model getSuperModel() 872 { 873 return superPomProvider.getSuperModel( "4.0.0" ).clone(); 874 } 875 876 private void importDependencyManagement( Model model, ModelBuildingRequest request, 877 DefaultModelProblemCollector problems, Collection<String> importIds ) 878 { 879 DependencyManagement depMngt = model.getDependencyManagement(); 880 881 if ( depMngt == null ) 882 { 883 return; 884 } 885 886 String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion(); 887 888 importIds.add( importing ); 889 890 ModelResolver modelResolver = request.getModelResolver(); 891 892 ModelBuildingRequest importRequest = null; 893 894 List<DependencyManagement> importMngts = null; 895 896 for ( Iterator<Dependency> it = depMngt.getDependencies().iterator(); it.hasNext(); ) 897 { 898 Dependency dependency = it.next(); 899 900 if ( !"pom".equals( dependency.getType() ) || !"import".equals( dependency.getScope() ) ) 901 { 902 continue; 903 } 904 905 it.remove(); 906 907 String groupId = dependency.getGroupId(); 908 String artifactId = dependency.getArtifactId(); 909 String version = dependency.getVersion(); 910 911 if ( groupId == null || groupId.length() <= 0 ) 912 { 913 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) 914 .setMessage( "'dependencyManagement.dependencies.dependency.groupId' for " 915 + dependency.getManagementKey() + " is missing." ) 916 .setLocation( dependency.getLocation( "" ) ) ); 917 continue; 918 } 919 if ( artifactId == null || artifactId.length() <= 0 ) 920 { 921 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) 922 .setMessage( "'dependencyManagement.dependencies.dependency.artifactId' for " 923 + 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 " 931 + dependency.getManagementKey() + " is missing." ) 932 .setLocation( dependency.getLocation( "" ) ) ); 933 continue; 934 } 935 936 String imported = groupId + ':' + artifactId + ':' + version; 937 938 if ( importIds.contains( imported ) ) 939 { 940 String message = "The dependencies of type=pom and with scope=import form a cycle: "; 941 for ( String modelId : importIds ) 942 { 943 message += modelId + " -> "; 944 } 945 message += imported; 946 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( message ) ); 947 948 continue; 949 } 950 951 DependencyManagement importMngt = 952 getCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT ); 953 954 if ( importMngt == null ) 955 { 956 if ( modelResolver == null ) 957 { 958 throw new IllegalArgumentException( "no model resolver provided, cannot resolve import POM " 959 + ModelProblemUtils.toId( groupId, artifactId, version ) + " for POM " 960 + ModelProblemUtils.toSourceHint( model ) ); 961 } 962 963 ModelSource importSource; 964 try 965 { 966 importSource = modelResolver.resolveModel( groupId, artifactId, version ); 967 } 968 catch ( UnresolvableModelException e ) 969 { 970 StringBuilder buffer = new StringBuilder( 256 ); 971 buffer.append( "Non-resolvable import POM" ); 972 if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) ) 973 { 974 buffer.append( " " ).append( ModelProblemUtils.toId( groupId, artifactId, version ) ); 975 } 976 buffer.append( ": " ).append( e.getMessage() ); 977 978 problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ) 979 .setMessage( buffer.toString() ) 980 .setLocation( dependency.getLocation( "" ) ) 981 .setException( e ) ); 982 continue; 983 } 984 985 if ( importRequest == null ) 986 { 987 importRequest = new DefaultModelBuildingRequest(); 988 importRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL ); 989 importRequest.setModelCache( request.getModelCache() ); 990 importRequest.setSystemProperties( request.getSystemProperties() ); 991 importRequest.setUserProperties( request.getUserProperties() ); 992 importRequest.setLocationTracking( request.isLocationTracking() ); 993 } 994 995 importRequest.setModelSource( importSource ); 996 importRequest.setModelResolver( modelResolver.newCopy() ); 997 998 ModelBuildingResult importResult; 999 try 1000 { 1001 importResult = build( importRequest ); 1002 } 1003 catch ( ModelBuildingException e ) 1004 { 1005 problems.addAll( e.getProblems() ); 1006 continue; 1007 } 1008 1009 problems.addAll( importResult.getProblems() ); 1010 1011 Model importModel = importResult.getEffectiveModel(); 1012 1013 importMngt = importModel.getDependencyManagement(); 1014 1015 if ( importMngt == null ) 1016 { 1017 importMngt = new DependencyManagement(); 1018 } 1019 1020 putCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMngt ); 1021 } 1022 1023 if ( importMngts == null ) 1024 { 1025 importMngts = new ArrayList<DependencyManagement>(); 1026 } 1027 1028 importMngts.add( importMngt ); 1029 } 1030 1031 importIds.remove( importing ); 1032 1033 dependencyManagementImporter.importManagement( model, importMngts, request, problems ); 1034 } 1035 1036 private <T> void putCache( ModelCache modelCache, String groupId, String artifactId, String version, 1037 ModelCacheTag<T> tag, T data ) 1038 { 1039 if ( modelCache != null ) 1040 { 1041 modelCache.put( groupId, artifactId, version, tag.getName(), tag.intoCache( data ) ); 1042 } 1043 } 1044 1045 private <T> T getCache( ModelCache modelCache, String groupId, String artifactId, String version, 1046 ModelCacheTag<T> tag ) 1047 { 1048 if ( modelCache != null ) 1049 { 1050 Object data = modelCache.get( groupId, artifactId, version, tag.getName() ); 1051 if ( data != null ) 1052 { 1053 return tag.fromCache( tag.getType().cast( data ) ); 1054 } 1055 } 1056 return null; 1057 } 1058 1059 private void fireEvent( Model model, ModelBuildingRequest request, ModelProblemCollector problems, 1060 ModelBuildingEventCatapult catapult ) 1061 throws ModelBuildingException 1062 { 1063 ModelBuildingListener listener = request.getModelBuildingListener(); 1064 1065 if ( listener != null ) 1066 { 1067 ModelBuildingEvent event = new DefaultModelBuildingEvent( model, request, problems ); 1068 1069 catapult.fire( listener, event ); 1070 } 1071 } 1072 1073 private boolean containsCoordinates( String message, String groupId, String artifactId, String version ) 1074 { 1075 return message != null && ( groupId == null || message.contains( groupId ) ) 1076 && ( artifactId == null || message.contains( artifactId ) ) 1077 && ( version == null || message.contains( version ) ); 1078 } 1079 1080 protected boolean hasModelErrors( ModelProblemCollectorExt problems ) 1081 { 1082 if ( problems instanceof DefaultModelProblemCollector ) 1083 { 1084 return ( (DefaultModelProblemCollector) problems ).hasErrors(); 1085 } 1086 else 1087 { 1088 // the default execution path only knows the DefaultModelProblemCollector, 1089 // only reason it's not in signature is because it's package private 1090 throw new IllegalStateException(); 1091 } 1092 } 1093 1094 protected boolean hasFatalErrors( ModelProblemCollectorExt problems ) 1095 { 1096 if ( problems instanceof DefaultModelProblemCollector ) 1097 { 1098 return ( (DefaultModelProblemCollector) problems ).hasFatalErrors(); 1099 } 1100 else 1101 { 1102 // the default execution path only knows the DefaultModelProblemCollector, 1103 // only reason it's not in signature is because it's package private 1104 throw new IllegalStateException(); 1105 } 1106 } 1107 1108}