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