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