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.building.ModelProblem.Version; 046 import org.apache.maven.model.composition.DependencyManagementImporter; 047 import org.apache.maven.model.inheritance.InheritanceAssembler; 048 import org.apache.maven.model.interpolation.ModelInterpolator; 049 import org.apache.maven.model.io.ModelParseException; 050 import org.apache.maven.model.management.DependencyManagementInjector; 051 import org.apache.maven.model.management.PluginManagementInjector; 052 import org.apache.maven.model.normalization.ModelNormalizer; 053 import org.apache.maven.model.path.ModelPathTranslator; 054 import org.apache.maven.model.path.ModelUrlNormalizer; 055 import org.apache.maven.model.plugin.LifecycleBindingsInjector; 056 import org.apache.maven.model.plugin.PluginConfigurationExpander; 057 import org.apache.maven.model.plugin.ReportConfigurationExpander; 058 import org.apache.maven.model.plugin.ReportingConverter; 059 import org.apache.maven.model.profile.DefaultProfileActivationContext; 060 import org.apache.maven.model.profile.ProfileInjector; 061 import org.apache.maven.model.profile.ProfileSelector; 062 import org.apache.maven.model.resolution.InvalidRepositoryException; 063 import org.apache.maven.model.resolution.ModelResolver; 064 import org.apache.maven.model.resolution.UnresolvableModelException; 065 import org.apache.maven.model.superpom.SuperPomProvider; 066 import org.apache.maven.model.validation.ModelValidator; 067 import org.codehaus.plexus.component.annotations.Component; 068 import org.codehaus.plexus.component.annotations.Requirement; 069 070 /** 071 * @author Benjamin Bentmann 072 */ 073 @Component( role = ModelBuilder.class ) 074 public 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( 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 // still unreadable even in non-strict mode, rethrow original error 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 // NOTE: There's java.nio.charset.MalformedInputException and sun.io.MalformedInputException 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 * NOTE: This is a sanity check of the cache hit. If the cached parent POM was locally resolved, the 676 * child's <relativePath> should point at that parent, too. If it doesn't, we ignore the cache and 677 * resolve externally, to mimic the behavior if the cache didn't exist in the first place. Otherwise, 678 * the cache would obscure a bad POM. 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 //the default execution path only knows the DefaultModelProblemCollector, 1084 // only reason it's not in signature is because it's package private 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 //the default execution path only knows the DefaultModelProblemCollector, 1095 // only reason it's not in signature is because it's package private 1096 throw new IllegalStateException(); 1097 } 1098 } 1099 1100 }