001package org.apache.maven.plugin.internal; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.BufferedInputStream; 023import java.io.ByteArrayOutputStream; 024import java.io.File; 025import java.io.FileInputStream; 026import java.io.IOException; 027import java.io.InputStream; 028import java.io.PrintStream; 029import java.io.Reader; 030import java.util.ArrayList; 031import java.util.Collection; 032import java.util.Collections; 033import java.util.HashMap; 034import java.util.Iterator; 035import java.util.List; 036import java.util.Map; 037import java.util.jar.JarFile; 038import java.util.zip.ZipEntry; 039 040import org.apache.maven.RepositoryUtils; 041import org.apache.maven.artifact.Artifact; 042import org.apache.maven.classrealm.ClassRealmManager; 043import org.apache.maven.execution.MavenSession; 044import org.apache.maven.model.Plugin; 045import org.apache.maven.monitor.logging.DefaultLog; 046import org.apache.maven.plugin.ContextEnabled; 047import org.apache.maven.plugin.DebugConfigurationListener; 048import org.apache.maven.plugin.InvalidPluginDescriptorException; 049import org.apache.maven.plugin.MavenPluginManager; 050import org.apache.maven.plugin.MavenPluginValidator; 051import org.apache.maven.plugin.Mojo; 052import org.apache.maven.plugin.MojoExecution; 053import org.apache.maven.plugin.MojoNotFoundException; 054import org.apache.maven.plugin.PluginConfigurationException; 055import org.apache.maven.plugin.PluginContainerException; 056import org.apache.maven.plugin.PluginDescriptorCache; 057import org.apache.maven.plugin.PluginDescriptorParsingException; 058import org.apache.maven.plugin.PluginIncompatibleException; 059import org.apache.maven.plugin.PluginParameterException; 060import org.apache.maven.plugin.PluginParameterExpressionEvaluator; 061import org.apache.maven.plugin.PluginRealmCache; 062import org.apache.maven.plugin.PluginResolutionException; 063import org.apache.maven.plugin.descriptor.MojoDescriptor; 064import org.apache.maven.plugin.descriptor.Parameter; 065import org.apache.maven.plugin.descriptor.PluginDescriptor; 066import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder; 067import org.apache.maven.project.MavenProject; 068import org.apache.maven.rtinfo.RuntimeInformation; 069import org.codehaus.plexus.PlexusContainer; 070import org.codehaus.plexus.classworlds.realm.ClassRealm; 071import org.codehaus.plexus.component.annotations.Component; 072import org.codehaus.plexus.component.annotations.Requirement; 073import org.codehaus.plexus.component.composition.CycleDetectedInComponentGraphException; 074import org.codehaus.plexus.component.configurator.ComponentConfigurationException; 075import org.codehaus.plexus.component.configurator.ComponentConfigurator; 076import org.codehaus.plexus.component.configurator.ConfigurationListener; 077import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; 078import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; 079import org.codehaus.plexus.component.repository.ComponentDescriptor; 080import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException; 081import org.codehaus.plexus.component.repository.exception.ComponentLookupException; 082import org.codehaus.plexus.configuration.PlexusConfiguration; 083import org.codehaus.plexus.configuration.PlexusConfigurationException; 084import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; 085import org.codehaus.plexus.logging.Logger; 086import org.codehaus.plexus.logging.LoggerManager; 087import org.codehaus.plexus.util.IOUtil; 088import org.codehaus.plexus.util.ReaderFactory; 089import org.codehaus.plexus.util.StringUtils; 090import org.codehaus.plexus.util.xml.Xpp3Dom; 091import org.eclipse.aether.RepositorySystemSession; 092import org.eclipse.aether.graph.DependencyFilter; 093import org.eclipse.aether.graph.DependencyNode; 094import org.eclipse.aether.repository.RemoteRepository; 095import org.eclipse.aether.util.filter.AndDependencyFilter; 096import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator; 097 098/** 099 * Provides basic services to manage Maven plugins and their mojos. This component is kept general in its design such 100 * that the plugins/mojos can be used in arbitrary contexts. In particular, the mojos can be used for ordinary build 101 * plugins as well as special purpose plugins like reports. 102 * 103 * @since 3.0 104 * @author Benjamin Bentmann 105 */ 106@Component( role = MavenPluginManager.class ) 107public class DefaultMavenPluginManager 108 implements MavenPluginManager 109{ 110 111 @Requirement 112 private Logger logger; 113 114 @Requirement 115 private LoggerManager loggerManager; 116 117 @Requirement 118 private PlexusContainer container; 119 120 @Requirement 121 private ClassRealmManager classRealmManager; 122 123 @Requirement 124 private PluginDescriptorCache pluginDescriptorCache; 125 126 @Requirement 127 private PluginRealmCache pluginRealmCache; 128 129 @Requirement 130 private PluginDependenciesResolver pluginDependenciesResolver; 131 132 @Requirement 133 private RuntimeInformation runtimeInformation; 134 135 private PluginDescriptorBuilder builder = new PluginDescriptorBuilder(); 136 137 public synchronized PluginDescriptor getPluginDescriptor( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session ) 138 throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException 139 { 140 PluginDescriptorCache.Key cacheKey = pluginDescriptorCache.createKey( plugin, repositories, session ); 141 142 PluginDescriptor pluginDescriptor = pluginDescriptorCache.get( cacheKey ); 143 144 if ( pluginDescriptor == null ) 145 { 146 org.eclipse.aether.artifact.Artifact artifact = 147 pluginDependenciesResolver.resolve( plugin, repositories, session ); 148 149 Artifact pluginArtifact = RepositoryUtils.toArtifact( artifact ); 150 151 pluginDescriptor = extractPluginDescriptor( pluginArtifact, plugin ); 152 153 pluginDescriptor.setRequiredMavenVersion( artifact.getProperty( "requiredMavenVersion", null ) ); 154 155 pluginDescriptorCache.put( cacheKey, pluginDescriptor ); 156 } 157 158 pluginDescriptor.setPlugin( plugin ); 159 160 return pluginDescriptor; 161 } 162 163 private PluginDescriptor extractPluginDescriptor( Artifact pluginArtifact, Plugin plugin ) 164 throws PluginDescriptorParsingException, InvalidPluginDescriptorException 165 { 166 PluginDescriptor pluginDescriptor = null; 167 168 File pluginFile = pluginArtifact.getFile(); 169 170 try 171 { 172 if ( pluginFile.isFile() ) 173 { 174 JarFile pluginJar = new JarFile( pluginFile, false ); 175 try 176 { 177 ZipEntry pluginDescriptorEntry = pluginJar.getEntry( getPluginDescriptorLocation() ); 178 179 if ( pluginDescriptorEntry != null ) 180 { 181 InputStream is = pluginJar.getInputStream( pluginDescriptorEntry ); 182 183 pluginDescriptor = parsePluginDescriptor( is, plugin, pluginFile.getAbsolutePath() ); 184 } 185 } 186 finally 187 { 188 pluginJar.close(); 189 } 190 } 191 else 192 { 193 File pluginXml = new File( pluginFile, getPluginDescriptorLocation() ); 194 195 if ( pluginXml.isFile() ) 196 { 197 InputStream is = new BufferedInputStream( new FileInputStream( pluginXml ) ); 198 try 199 { 200 pluginDescriptor = parsePluginDescriptor( is, plugin, pluginXml.getAbsolutePath() ); 201 } 202 finally 203 { 204 IOUtil.close( is ); 205 } 206 } 207 } 208 209 if ( pluginDescriptor == null ) 210 { 211 throw new IOException( "No plugin descriptor found at " + getPluginDescriptorLocation() ); 212 } 213 } 214 catch ( IOException e ) 215 { 216 throw new PluginDescriptorParsingException( plugin, pluginFile.getAbsolutePath(), e ); 217 } 218 219 MavenPluginValidator validator = new MavenPluginValidator( pluginArtifact ); 220 221 validator.validate( pluginDescriptor ); 222 223 if ( validator.hasErrors() ) 224 { 225 throw new InvalidPluginDescriptorException( "Invalid plugin descriptor for " + plugin.getId() + " (" 226 + pluginFile + ")", validator.getErrors() ); 227 } 228 229 pluginDescriptor.setPluginArtifact( pluginArtifact ); 230 231 return pluginDescriptor; 232 } 233 234 private String getPluginDescriptorLocation() 235 { 236 return "META-INF/maven/plugin.xml"; 237 } 238 239 private PluginDescriptor parsePluginDescriptor( InputStream is, Plugin plugin, String descriptorLocation ) 240 throws PluginDescriptorParsingException 241 { 242 try 243 { 244 Reader reader = ReaderFactory.newXmlReader( is ); 245 246 PluginDescriptor pluginDescriptor = builder.build( reader, descriptorLocation ); 247 248 return pluginDescriptor; 249 } 250 catch ( IOException e ) 251 { 252 throw new PluginDescriptorParsingException( plugin, descriptorLocation, e ); 253 } 254 catch ( PlexusConfigurationException e ) 255 { 256 throw new PluginDescriptorParsingException( plugin, descriptorLocation, e ); 257 } 258 } 259 260 public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List<RemoteRepository> repositories, 261 RepositorySystemSession session ) 262 throws MojoNotFoundException, PluginResolutionException, PluginDescriptorParsingException, 263 InvalidPluginDescriptorException 264 { 265 PluginDescriptor pluginDescriptor = getPluginDescriptor( plugin, repositories, session ); 266 267 MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( goal ); 268 269 if ( mojoDescriptor == null ) 270 { 271 throw new MojoNotFoundException( goal, pluginDescriptor ); 272 } 273 274 return mojoDescriptor; 275 } 276 277 public void checkRequiredMavenVersion( PluginDescriptor pluginDescriptor ) 278 throws PluginIncompatibleException 279 { 280 String requiredMavenVersion = pluginDescriptor.getRequiredMavenVersion(); 281 if ( StringUtils.isNotBlank( requiredMavenVersion ) ) 282 { 283 try 284 { 285 if ( !runtimeInformation.isMavenVersion( requiredMavenVersion ) ) 286 { 287 throw new PluginIncompatibleException( pluginDescriptor.getPlugin(), "The plugin " 288 + pluginDescriptor.getId() + " requires Maven version " + requiredMavenVersion ); 289 } 290 } 291 catch ( RuntimeException e ) 292 { 293 logger.warn( "Could not verify plugin's Maven prerequisite: " + e.getMessage() ); 294 } 295 } 296 } 297 298 public synchronized void setupPluginRealm( PluginDescriptor pluginDescriptor, MavenSession session, 299 ClassLoader parent, List<String> imports, DependencyFilter filter ) 300 throws PluginResolutionException, PluginContainerException 301 { 302 Plugin plugin = pluginDescriptor.getPlugin(); 303 304 MavenProject project = session.getCurrentProject(); 305 306 Map<String, ClassLoader> foreignImports = calcImports( project, parent, imports ); 307 308 PluginRealmCache.Key cacheKey = 309 pluginRealmCache.createKey( plugin, parent, foreignImports, filter, project.getRemotePluginRepositories(), 310 session.getRepositorySession() ); 311 312 PluginRealmCache.CacheRecord cacheRecord = pluginRealmCache.get( cacheKey ); 313 314 if ( cacheRecord != null ) 315 { 316 pluginDescriptor.setClassRealm( cacheRecord.realm ); 317 pluginDescriptor.setArtifacts( new ArrayList<Artifact>( cacheRecord.artifacts ) ); 318 for ( ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents() ) 319 { 320 componentDescriptor.setRealm( cacheRecord.realm ); 321 } 322 } 323 else 324 { 325 createPluginRealm( pluginDescriptor, session, parent, foreignImports, filter ); 326 327 cacheRecord = 328 pluginRealmCache.put( cacheKey, pluginDescriptor.getClassRealm(), pluginDescriptor.getArtifacts() ); 329 } 330 331 pluginRealmCache.register( project, cacheRecord ); 332 } 333 334 private void createPluginRealm( PluginDescriptor pluginDescriptor, MavenSession session, ClassLoader parent, 335 Map<String, ClassLoader> foreignImports, DependencyFilter filter ) 336 throws PluginResolutionException, PluginContainerException 337 { 338 Plugin plugin = pluginDescriptor.getPlugin(); 339 340 if ( plugin == null ) 341 { 342 throw new IllegalArgumentException( "incomplete plugin descriptor, plugin missing" ); 343 } 344 345 Artifact pluginArtifact = pluginDescriptor.getPluginArtifact(); 346 347 if ( pluginArtifact == null ) 348 { 349 throw new IllegalArgumentException( "incomplete plugin descriptor, plugin artifact missing" ); 350 } 351 352 MavenProject project = session.getCurrentProject(); 353 354 DependencyFilter dependencyFilter = project.getExtensionDependencyFilter(); 355 dependencyFilter = AndDependencyFilter.newInstance( dependencyFilter, filter ); 356 357 DependencyNode root = 358 pluginDependenciesResolver.resolve( plugin, RepositoryUtils.toArtifact( pluginArtifact ), dependencyFilter, 359 project.getRemotePluginRepositories(), session.getRepositorySession() ); 360 361 PreorderNodeListGenerator nlg = new PreorderNodeListGenerator(); 362 root.accept( nlg ); 363 364 List<Artifact> exposedPluginArtifacts = new ArrayList<Artifact>( nlg.getNodes().size() ); 365 RepositoryUtils.toArtifacts( exposedPluginArtifacts, Collections.singleton( root ), 366 Collections.<String> emptyList(), null ); 367 for ( Iterator<Artifact> it = exposedPluginArtifacts.iterator(); it.hasNext(); ) 368 { 369 Artifact artifact = it.next(); 370 if ( artifact.getFile() == null ) 371 { 372 it.remove(); 373 } 374 } 375 376 List<org.eclipse.aether.artifact.Artifact> pluginArtifacts = nlg.getArtifacts( true ); 377 378 ClassRealm pluginRealm = 379 classRealmManager.createPluginRealm( plugin, parent, null, foreignImports, pluginArtifacts ); 380 381 pluginDescriptor.setClassRealm( pluginRealm ); 382 pluginDescriptor.setArtifacts( exposedPluginArtifacts ); 383 384 try 385 { 386 for ( ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents() ) 387 { 388 componentDescriptor.setRealm( pluginRealm ); 389 container.addComponentDescriptor( componentDescriptor ); 390 } 391 392 container.discoverComponents( pluginRealm ); 393 } 394 catch ( PlexusConfigurationException e ) 395 { 396 throw new PluginContainerException( plugin, pluginRealm, "Error in component graph of plugin " 397 + plugin.getId() + ": " + e.getMessage(), e ); 398 } 399 catch ( CycleDetectedInComponentGraphException e ) 400 { 401 throw new PluginContainerException( plugin, pluginRealm, "Error in component graph of plugin " 402 + plugin.getId() + ": " + e.getMessage(), e ); 403 } 404 } 405 406 private Map<String, ClassLoader> calcImports( MavenProject project, ClassLoader parent, List<String> imports ) 407 { 408 Map<String, ClassLoader> foreignImports = new HashMap<String, ClassLoader>(); 409 410 ClassLoader projectRealm = project.getClassRealm(); 411 if ( projectRealm != null ) 412 { 413 foreignImports.put( "", projectRealm ); 414 } 415 else 416 { 417 foreignImports.put( "", classRealmManager.getMavenApiRealm() ); 418 } 419 420 if ( parent != null && imports != null ) 421 { 422 for ( String parentImport : imports ) 423 { 424 foreignImports.put( parentImport, parent ); 425 } 426 } 427 428 return foreignImports; 429 } 430 431 public <T> T getConfiguredMojo( Class<T> mojoInterface, MavenSession session, MojoExecution mojoExecution ) 432 throws PluginConfigurationException, PluginContainerException 433 { 434 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor(); 435 436 PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor(); 437 438 ClassRealm pluginRealm = pluginDescriptor.getClassRealm(); 439 440 if ( logger.isDebugEnabled() ) 441 { 442 logger.debug( "Configuring mojo " + mojoDescriptor.getId() + " from plugin realm " + pluginRealm ); 443 } 444 445 // We are forcing the use of the plugin realm for all lookups that might occur during 446 // the lifecycle that is part of the lookup. Here we are specifically trying to keep 447 // lookups that occur in contextualize calls in line with the right realm. 448 ClassRealm oldLookupRealm = container.setLookupRealm( pluginRealm ); 449 450 ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); 451 Thread.currentThread().setContextClassLoader( pluginRealm ); 452 453 try 454 { 455 T mojo; 456 457 try 458 { 459 mojo = container.lookup( mojoInterface, mojoDescriptor.getRoleHint() ); 460 } 461 catch ( ComponentLookupException e ) 462 { 463 Throwable cause = e.getCause(); 464 while ( cause != null && !( cause instanceof LinkageError ) 465 && !( cause instanceof ClassNotFoundException ) ) 466 { 467 cause = cause.getCause(); 468 } 469 470 if ( ( cause instanceof NoClassDefFoundError ) || ( cause instanceof ClassNotFoundException ) ) 471 { 472 ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 ); 473 PrintStream ps = new PrintStream( os ); 474 ps.println( "Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '" 475 + pluginDescriptor.getId() + "'. A required class is missing: " + cause.getMessage() ); 476 pluginRealm.display( ps ); 477 478 throw new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), cause ); 479 } 480 else if ( cause instanceof LinkageError ) 481 { 482 ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 ); 483 PrintStream ps = new PrintStream( os ); 484 ps.println( "Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '" 485 + pluginDescriptor.getId() + "' due to an API incompatibility: " + e.getClass().getName() 486 + ": " + cause.getMessage() ); 487 pluginRealm.display( ps ); 488 489 throw new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), cause ); 490 } 491 492 throw new PluginContainerException( mojoDescriptor, pluginRealm, "Unable to load the mojo '" 493 + mojoDescriptor.getGoal() + "' (or one of its required components) from the plugin '" 494 + pluginDescriptor.getId() + "'", e ); 495 } 496 497 if ( mojo instanceof ContextEnabled ) 498 { 499 MavenProject project = session.getCurrentProject(); 500 501 Map<String, Object> pluginContext = session.getPluginContext( pluginDescriptor, project ); 502 503 if ( pluginContext != null ) 504 { 505 pluginContext.put( "project", project ); 506 507 pluginContext.put( "pluginDescriptor", pluginDescriptor ); 508 509 ( (ContextEnabled) mojo ).setPluginContext( pluginContext ); 510 } 511 } 512 513 if ( mojo instanceof Mojo ) 514 { 515 Logger mojoLogger = loggerManager.getLoggerForComponent( mojoDescriptor.getImplementation() ); 516 ( (Mojo) mojo ).setLog( new DefaultLog( mojoLogger ) ); 517 } 518 519 Xpp3Dom dom = mojoExecution.getConfiguration(); 520 521 PlexusConfiguration pomConfiguration; 522 523 if ( dom == null ) 524 { 525 pomConfiguration = new XmlPlexusConfiguration( "configuration" ); 526 } 527 else 528 { 529 pomConfiguration = new XmlPlexusConfiguration( dom ); 530 } 531 532 ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator( session, mojoExecution ); 533 534 populatePluginFields( mojo, mojoDescriptor, pluginRealm, pomConfiguration, expressionEvaluator ); 535 536 return mojo; 537 } 538 finally 539 { 540 Thread.currentThread().setContextClassLoader( oldClassLoader ); 541 container.setLookupRealm( oldLookupRealm ); 542 } 543 } 544 545 private void populatePluginFields( Object mojo, MojoDescriptor mojoDescriptor, ClassRealm pluginRealm, 546 PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator ) 547 throws PluginConfigurationException 548 { 549 ComponentConfigurator configurator = null; 550 551 String configuratorId = mojoDescriptor.getComponentConfigurator(); 552 553 if ( StringUtils.isEmpty( configuratorId ) ) 554 { 555 configuratorId = "basic"; 556 } 557 558 try 559 { 560 // TODO: could the configuration be passed to lookup and the configurator known to plexus via the descriptor 561 // so that this method could entirely be handled by a plexus lookup? 562 configurator = container.lookup( ComponentConfigurator.class, configuratorId ); 563 564 ConfigurationListener listener = new DebugConfigurationListener( logger ); 565 566 ValidatingConfigurationListener validator = 567 new ValidatingConfigurationListener( mojo, mojoDescriptor, listener ); 568 569 logger.debug( "Configuring mojo '" + mojoDescriptor.getId() + "' with " + configuratorId 570 + " configurator -->" ); 571 572 configurator.configureComponent( mojo, configuration, expressionEvaluator, pluginRealm, validator ); 573 574 logger.debug( "-- end configuration --" ); 575 576 Collection<Parameter> missingParameters = validator.getMissingParameters(); 577 if ( !missingParameters.isEmpty() ) 578 { 579 if ( "basic".equals( configuratorId ) ) 580 { 581 throw new PluginParameterException( mojoDescriptor, new ArrayList<Parameter>( missingParameters ) ); 582 } 583 else 584 { 585 /* 586 * NOTE: Other configurators like the map-oriented one don't call into the listener, so do it the 587 * hard way. 588 */ 589 validateParameters( mojoDescriptor, configuration, expressionEvaluator ); 590 } 591 } 592 } 593 catch ( ComponentConfigurationException e ) 594 { 595 String message = "Unable to parse configuration of mojo " + mojoDescriptor.getId(); 596 if ( e.getFailedConfiguration() != null ) 597 { 598 message += " for parameter " + e.getFailedConfiguration().getName(); 599 } 600 message += ": " + e.getMessage(); 601 602 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), message, e ); 603 } 604 catch ( ComponentLookupException e ) 605 { 606 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), 607 "Unable to retrieve component configurator " + configuratorId 608 + " for configuration of mojo " + mojoDescriptor.getId(), e ); 609 } 610 catch ( NoClassDefFoundError e ) 611 { 612 ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 ); 613 PrintStream ps = new PrintStream( os ); 614 ps.println( "A required class was missing during configuration of mojo " + mojoDescriptor.getId() + ": " 615 + e.getMessage() ); 616 pluginRealm.display( ps ); 617 618 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), os.toString(), e ); 619 } 620 catch ( LinkageError e ) 621 { 622 ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 ); 623 PrintStream ps = new PrintStream( os ); 624 ps.println( "An API incompatibility was encountered during configuration of mojo " + mojoDescriptor.getId() 625 + ": " + e.getClass().getName() + ": " + e.getMessage() ); 626 pluginRealm.display( ps ); 627 628 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), os.toString(), e ); 629 } 630 finally 631 { 632 if ( configurator != null ) 633 { 634 try 635 { 636 container.release( configurator ); 637 } 638 catch ( ComponentLifecycleException e ) 639 { 640 logger.debug( "Failed to release mojo configurator - ignoring." ); 641 } 642 } 643 } 644 } 645 646 private void validateParameters( MojoDescriptor mojoDescriptor, PlexusConfiguration configuration, 647 ExpressionEvaluator expressionEvaluator ) 648 throws ComponentConfigurationException, PluginParameterException 649 { 650 if ( mojoDescriptor.getParameters() == null ) 651 { 652 return; 653 } 654 655 List<Parameter> invalidParameters = new ArrayList<Parameter>(); 656 657 for ( Parameter parameter : mojoDescriptor.getParameters() ) 658 { 659 if ( !parameter.isRequired() ) 660 { 661 continue; 662 } 663 664 Object value = null; 665 666 PlexusConfiguration config = configuration.getChild( parameter.getName(), false ); 667 if ( config != null ) 668 { 669 String expression = config.getValue( null ); 670 671 try 672 { 673 value = expressionEvaluator.evaluate( expression ); 674 675 if ( value == null ) 676 { 677 value = config.getAttribute( "default-value", null ); 678 } 679 } 680 catch ( ExpressionEvaluationException e ) 681 { 682 String msg = 683 "Error evaluating the expression '" + expression + "' for configuration value '" 684 + configuration.getName() + "'"; 685 throw new ComponentConfigurationException( configuration, msg, e ); 686 } 687 } 688 689 if ( value == null && ( config == null || config.getChildCount() <= 0 ) ) 690 { 691 invalidParameters.add( parameter ); 692 } 693 } 694 695 if ( !invalidParameters.isEmpty() ) 696 { 697 throw new PluginParameterException( mojoDescriptor, invalidParameters ); 698 } 699 } 700 701 public void releaseMojo( Object mojo, MojoExecution mojoExecution ) 702 { 703 if ( mojo != null ) 704 { 705 try 706 { 707 container.release( mojo ); 708 } 709 catch ( ComponentLifecycleException e ) 710 { 711 String goalExecId = mojoExecution.getGoal(); 712 713 if ( mojoExecution.getExecutionId() != null ) 714 { 715 goalExecId += " {execution: " + mojoExecution.getExecutionId() + "}"; 716 } 717 718 logger.debug( "Error releasing mojo for " + goalExecId, e ); 719 } 720 } 721 } 722 723}