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