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