Java tutorial
package org.apache.maven.plugin.internal; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import org.apache.commons.lang3.Validate; import org.apache.maven.RepositoryUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.classrealm.ClassRealmManager; import org.apache.maven.execution.MavenSession; import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule; import org.apache.maven.model.Plugin; import org.apache.maven.monitor.logging.DefaultLog; import org.apache.maven.plugin.ContextEnabled; import org.apache.maven.plugin.DebugConfigurationListener; import org.apache.maven.plugin.ExtensionRealmCache; import org.apache.maven.plugin.InvalidPluginDescriptorException; import org.apache.maven.plugin.MavenPluginManager; import org.apache.maven.plugin.MavenPluginValidator; import org.apache.maven.plugin.Mojo; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoNotFoundException; import org.apache.maven.plugin.PluginArtifactsCache; import org.apache.maven.plugin.PluginConfigurationException; import org.apache.maven.plugin.PluginContainerException; import org.apache.maven.plugin.PluginDescriptorCache; import org.apache.maven.plugin.PluginDescriptorParsingException; import org.apache.maven.plugin.PluginIncompatibleException; import org.apache.maven.plugin.PluginManagerException; import org.apache.maven.plugin.PluginParameterException; import org.apache.maven.plugin.PluginParameterExpressionEvaluator; import org.apache.maven.plugin.PluginRealmCache; import org.apache.maven.plugin.PluginResolutionException; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.Parameter; import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder; import org.apache.maven.plugin.version.DefaultPluginVersionRequest; import org.apache.maven.plugin.version.PluginVersionRequest; import org.apache.maven.plugin.version.PluginVersionResolutionException; import org.apache.maven.plugin.version.PluginVersionResolver; import org.apache.maven.project.ExtensionDescriptor; import org.apache.maven.project.ExtensionDescriptorBuilder; import org.apache.maven.project.MavenProject; import org.apache.maven.rtinfo.RuntimeInformation; import org.apache.maven.session.scope.internal.SessionScopeModule; import org.codehaus.plexus.DefaultPlexusContainer; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.classworlds.realm.ClassRealm; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Requirement; import org.codehaus.plexus.component.composition.CycleDetectedInComponentGraphException; import org.codehaus.plexus.component.configurator.ComponentConfigurationException; import org.codehaus.plexus.component.configurator.ComponentConfigurator; import org.codehaus.plexus.component.configurator.ConfigurationListener; import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; import org.codehaus.plexus.component.repository.ComponentDescriptor; import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.codehaus.plexus.configuration.PlexusConfiguration; import org.codehaus.plexus.configuration.PlexusConfigurationException; import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.logging.LoggerManager; import org.codehaus.plexus.util.ReaderFactory; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.graph.DependencyFilter; import org.eclipse.aether.graph.DependencyNode; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.util.filter.AndDependencyFilter; import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.io.Reader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.jar.JarFile; import java.util.zip.ZipEntry; /** * Provides basic services to manage Maven plugins and their mojos. This component is kept general in its design such * that the plugins/mojos can be used in arbitrary contexts. In particular, the mojos can be used for ordinary build * plugins as well as special purpose plugins like reports. * * @author Benjamin Bentmann * @since 3.0 */ @Component(role = MavenPluginManager.class) public class DefaultMavenPluginManager implements MavenPluginManager { /** * PluginId=>ExtensionRealmCache.CacheRecord map MavenProject context value key. The map is used to ensure the same * class realm is used to load build extensions and load mojos for extensions=true plugins. * * @noreference this is part of internal implementation and may be changed or removed without notice * @since 3.3.0 */ public static final String KEY_EXTENSIONS_REALMS = DefaultMavenPluginManager.class.getName() + "/extensionsRealms"; @Requirement private Logger logger; @Requirement private LoggerManager loggerManager; @Requirement private PlexusContainer container; @Requirement private ClassRealmManager classRealmManager; @Requirement private PluginDescriptorCache pluginDescriptorCache; @Requirement private PluginRealmCache pluginRealmCache; @Requirement private PluginDependenciesResolver pluginDependenciesResolver; @Requirement private RuntimeInformation runtimeInformation; @Requirement private ExtensionRealmCache extensionRealmCache; @Requirement private PluginVersionResolver pluginVersionResolver; @Requirement private PluginArtifactsCache pluginArtifactsCache; private ExtensionDescriptorBuilder extensionDescriptorBuilder = new ExtensionDescriptorBuilder(); private PluginDescriptorBuilder builder = new PluginDescriptorBuilder(); public synchronized PluginDescriptor getPluginDescriptor(Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session) throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException { PluginDescriptorCache.Key cacheKey = pluginDescriptorCache.createKey(plugin, repositories, session); PluginDescriptor pluginDescriptor = pluginDescriptorCache.get(cacheKey); if (pluginDescriptor == null) { org.eclipse.aether.artifact.Artifact artifact = pluginDependenciesResolver.resolve(plugin, repositories, session); Artifact pluginArtifact = RepositoryUtils.toArtifact(artifact); pluginDescriptor = extractPluginDescriptor(pluginArtifact, plugin); pluginDescriptor.setRequiredMavenVersion(artifact.getProperty("requiredMavenVersion", null)); pluginDescriptorCache.put(cacheKey, pluginDescriptor); } pluginDescriptor.setPlugin(plugin); return pluginDescriptor; } private PluginDescriptor extractPluginDescriptor(Artifact pluginArtifact, Plugin plugin) throws PluginDescriptorParsingException, InvalidPluginDescriptorException { PluginDescriptor pluginDescriptor = null; File pluginFile = pluginArtifact.getFile(); try { if (pluginFile.isFile()) { try (JarFile pluginJar = new JarFile(pluginFile, false)) { ZipEntry pluginDescriptorEntry = pluginJar.getEntry(getPluginDescriptorLocation()); if (pluginDescriptorEntry != null) { InputStream is = pluginJar.getInputStream(pluginDescriptorEntry); pluginDescriptor = parsePluginDescriptor(is, plugin, pluginFile.getAbsolutePath()); } } } else { File pluginXml = new File(pluginFile, getPluginDescriptorLocation()); if (pluginXml.isFile()) { try (InputStream is = new BufferedInputStream(new FileInputStream(pluginXml))) { pluginDescriptor = parsePluginDescriptor(is, plugin, pluginXml.getAbsolutePath()); } } } if (pluginDescriptor == null) { throw new IOException("No plugin descriptor found at " + getPluginDescriptorLocation()); } } catch (IOException e) { throw new PluginDescriptorParsingException(plugin, pluginFile.getAbsolutePath(), e); } MavenPluginValidator validator = new MavenPluginValidator(pluginArtifact); validator.validate(pluginDescriptor); if (validator.hasErrors()) { throw new InvalidPluginDescriptorException( "Invalid plugin descriptor for " + plugin.getId() + " (" + pluginFile + ")", validator.getErrors()); } pluginDescriptor.setPluginArtifact(pluginArtifact); return pluginDescriptor; } private String getPluginDescriptorLocation() { return "META-INF/maven/plugin.xml"; } private PluginDescriptor parsePluginDescriptor(InputStream is, Plugin plugin, String descriptorLocation) throws PluginDescriptorParsingException { try { Reader reader = ReaderFactory.newXmlReader(is); PluginDescriptor pluginDescriptor = builder.build(reader, descriptorLocation); return pluginDescriptor; } catch (IOException | PlexusConfigurationException e) { throw new PluginDescriptorParsingException(plugin, descriptorLocation, e); } } public MojoDescriptor getMojoDescriptor(Plugin plugin, String goal, List<RemoteRepository> repositories, RepositorySystemSession session) throws MojoNotFoundException, PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException { PluginDescriptor pluginDescriptor = getPluginDescriptor(plugin, repositories, session); MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo(goal); if (mojoDescriptor == null) { throw new MojoNotFoundException(goal, pluginDescriptor); } return mojoDescriptor; } public void checkRequiredMavenVersion(PluginDescriptor pluginDescriptor) throws PluginIncompatibleException { String requiredMavenVersion = pluginDescriptor.getRequiredMavenVersion(); if (StringUtils.isNotBlank(requiredMavenVersion)) { try { if (!runtimeInformation.isMavenVersion(requiredMavenVersion)) { throw new PluginIncompatibleException(pluginDescriptor.getPlugin(), "The plugin " + pluginDescriptor.getId() + " requires Maven version " + requiredMavenVersion); } } catch (RuntimeException e) { logger.warn("Could not verify plugin's Maven prerequisite: " + e.getMessage()); } } } public synchronized void setupPluginRealm(PluginDescriptor pluginDescriptor, MavenSession session, ClassLoader parent, List<String> imports, DependencyFilter filter) throws PluginResolutionException, PluginContainerException { Plugin plugin = pluginDescriptor.getPlugin(); MavenProject project = session.getCurrentProject(); if (plugin.isExtensions()) { ExtensionRealmCache.CacheRecord extensionRecord; try { RepositorySystemSession repositorySession = session.getRepositorySession(); extensionRecord = setupExtensionsRealm(project, plugin, repositorySession); } catch (PluginManagerException e) { // extensions realm is expected to be fully setup at this point // any exception means a problem in maven code, not a user error throw new IllegalStateException(e); } ClassRealm pluginRealm = extensionRecord.realm; List<Artifact> pluginArtifacts = extensionRecord.artifacts; for (ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents()) { componentDescriptor.setRealm(pluginRealm); } pluginDescriptor.setClassRealm(pluginRealm); pluginDescriptor.setArtifacts(pluginArtifacts); } else { Map<String, ClassLoader> foreignImports = calcImports(project, parent, imports); PluginRealmCache.Key cacheKey = pluginRealmCache.createKey(plugin, parent, foreignImports, filter, project.getRemotePluginRepositories(), session.getRepositorySession()); PluginRealmCache.CacheRecord cacheRecord = pluginRealmCache.get(cacheKey); if (cacheRecord != null) { pluginDescriptor.setClassRealm(cacheRecord.realm); pluginDescriptor.setArtifacts(new ArrayList<>(cacheRecord.artifacts)); for (ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents()) { componentDescriptor.setRealm(cacheRecord.realm); } } else { createPluginRealm(pluginDescriptor, session, parent, foreignImports, filter); cacheRecord = pluginRealmCache.put(cacheKey, pluginDescriptor.getClassRealm(), pluginDescriptor.getArtifacts()); } pluginRealmCache.register(project, cacheKey, cacheRecord); } } private void createPluginRealm(PluginDescriptor pluginDescriptor, MavenSession session, ClassLoader parent, Map<String, ClassLoader> foreignImports, DependencyFilter filter) throws PluginResolutionException, PluginContainerException { Plugin plugin = Validate.notNull(pluginDescriptor.getPlugin(), "pluginDescriptor.plugin cannot be null"); Artifact pluginArtifact = Validate.notNull(pluginDescriptor.getPluginArtifact(), "pluginDescriptor.pluginArtifact cannot be null"); MavenProject project = session.getCurrentProject(); final ClassRealm pluginRealm; final List<Artifact> pluginArtifacts; RepositorySystemSession repositorySession = session.getRepositorySession(); DependencyFilter dependencyFilter = project.getExtensionDependencyFilter(); dependencyFilter = AndDependencyFilter.newInstance(dependencyFilter, filter); DependencyNode root = pluginDependenciesResolver.resolve(plugin, RepositoryUtils.toArtifact(pluginArtifact), dependencyFilter, project.getRemotePluginRepositories(), repositorySession); PreorderNodeListGenerator nlg = new PreorderNodeListGenerator(); root.accept(nlg); pluginArtifacts = toMavenArtifacts(root, nlg); pluginRealm = classRealmManager.createPluginRealm(plugin, parent, null, foreignImports, toAetherArtifacts(pluginArtifacts)); discoverPluginComponents(pluginRealm, plugin, pluginDescriptor); pluginDescriptor.setClassRealm(pluginRealm); pluginDescriptor.setArtifacts(pluginArtifacts); } private void discoverPluginComponents(final ClassRealm pluginRealm, Plugin plugin, PluginDescriptor pluginDescriptor) throws PluginContainerException { try { if (pluginDescriptor != null) { for (ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents()) { componentDescriptor.setRealm(pluginRealm); container.addComponentDescriptor(componentDescriptor); } } ((DefaultPlexusContainer) container).discoverComponents(pluginRealm, new SessionScopeModule(container), new MojoExecutionScopeModule(container)); } catch (ComponentLookupException | CycleDetectedInComponentGraphException e) { throw new PluginContainerException(plugin, pluginRealm, "Error in component graph of plugin " + plugin.getId() + ": " + e.getMessage(), e); } } private List<org.eclipse.aether.artifact.Artifact> toAetherArtifacts(final List<Artifact> pluginArtifacts) { return new ArrayList<>(RepositoryUtils.toArtifacts(pluginArtifacts)); } private List<Artifact> toMavenArtifacts(DependencyNode root, PreorderNodeListGenerator nlg) { List<Artifact> artifacts = new ArrayList<>(nlg.getNodes().size()); RepositoryUtils.toArtifacts(artifacts, Collections.singleton(root), Collections.<String>emptyList(), null); for (Iterator<Artifact> it = artifacts.iterator(); it.hasNext();) { Artifact artifact = it.next(); if (artifact.getFile() == null) { it.remove(); } } return Collections.unmodifiableList(artifacts); } private Map<String, ClassLoader> calcImports(MavenProject project, ClassLoader parent, List<String> imports) { Map<String, ClassLoader> foreignImports = new HashMap<>(); ClassLoader projectRealm = project.getClassRealm(); if (projectRealm != null) { foreignImports.put("", projectRealm); } else { foreignImports.put("", classRealmManager.getMavenApiRealm()); } if (parent != null && imports != null) { for (String parentImport : imports) { foreignImports.put(parentImport, parent); } } return foreignImports; } public <T> T getConfiguredMojo(Class<T> mojoInterface, MavenSession session, MojoExecution mojoExecution) throws PluginConfigurationException, PluginContainerException { MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor(); PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor(); ClassRealm pluginRealm = pluginDescriptor.getClassRealm(); if (logger.isDebugEnabled()) { logger.debug("Configuring mojo " + mojoDescriptor.getId() + " from plugin realm " + pluginRealm); } // We are forcing the use of the plugin realm for all lookups that might occur during // the lifecycle that is part of the lookup. Here we are specifically trying to keep // lookups that occur in contextualize calls in line with the right realm. ClassRealm oldLookupRealm = container.setLookupRealm(pluginRealm); ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(pluginRealm); try { T mojo; try { mojo = container.lookup(mojoInterface, mojoDescriptor.getRoleHint()); } catch (ComponentLookupException e) { Throwable cause = e.getCause(); while (cause != null && !(cause instanceof LinkageError) && !(cause instanceof ClassNotFoundException)) { cause = cause.getCause(); } if ((cause instanceof NoClassDefFoundError) || (cause instanceof ClassNotFoundException)) { ByteArrayOutputStream os = new ByteArrayOutputStream(1024); PrintStream ps = new PrintStream(os); ps.println("Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '" + pluginDescriptor.getId() + "'. A required class is missing: " + cause.getMessage()); pluginRealm.display(ps); throw new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), cause); } else if (cause instanceof LinkageError) { ByteArrayOutputStream os = new ByteArrayOutputStream(1024); PrintStream ps = new PrintStream(os); ps.println("Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '" + pluginDescriptor.getId() + "' due to an API incompatibility: " + e.getClass().getName() + ": " + cause.getMessage()); pluginRealm.display(ps); throw new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), cause); } throw new PluginContainerException(mojoDescriptor, pluginRealm, "Unable to load the mojo '" + mojoDescriptor.getGoal() + "' (or one of its required components) from the plugin '" + pluginDescriptor.getId() + "'", e); } if (mojo instanceof ContextEnabled) { MavenProject project = session.getCurrentProject(); Map<String, Object> pluginContext = session.getPluginContext(pluginDescriptor, project); if (pluginContext != null) { pluginContext.put("project", project); pluginContext.put("pluginDescriptor", pluginDescriptor); ((ContextEnabled) mojo).setPluginContext(pluginContext); } } if (mojo instanceof Mojo) { Logger mojoLogger = loggerManager.getLoggerForComponent(mojoDescriptor.getImplementation()); ((Mojo) mojo).setLog(new DefaultLog(mojoLogger)); } Xpp3Dom dom = mojoExecution.getConfiguration(); PlexusConfiguration pomConfiguration; if (dom == null) { pomConfiguration = new XmlPlexusConfiguration("configuration"); } else { pomConfiguration = new XmlPlexusConfiguration(dom); } ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator(session, mojoExecution); populatePluginFields(mojo, mojoDescriptor, pluginRealm, pomConfiguration, expressionEvaluator); return mojo; } finally { Thread.currentThread().setContextClassLoader(oldClassLoader); container.setLookupRealm(oldLookupRealm); } } private void populatePluginFields(Object mojo, MojoDescriptor mojoDescriptor, ClassRealm pluginRealm, PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator) throws PluginConfigurationException { ComponentConfigurator configurator = null; String configuratorId = mojoDescriptor.getComponentConfigurator(); if (StringUtils.isEmpty(configuratorId)) { configuratorId = "basic"; } try { // TODO: could the configuration be passed to lookup and the configurator known to plexus via the descriptor // so that this method could entirely be handled by a plexus lookup? configurator = container.lookup(ComponentConfigurator.class, configuratorId); ConfigurationListener listener = new DebugConfigurationListener(logger); ValidatingConfigurationListener validator = new ValidatingConfigurationListener(mojo, mojoDescriptor, listener); logger.debug("Configuring mojo '" + mojoDescriptor.getId() + "' with " + configuratorId + " configurator -->"); configurator.configureComponent(mojo, configuration, expressionEvaluator, pluginRealm, validator); logger.debug("-- end configuration --"); Collection<Parameter> missingParameters = validator.getMissingParameters(); if (!missingParameters.isEmpty()) { if ("basic".equals(configuratorId)) { throw new PluginParameterException(mojoDescriptor, new ArrayList<>(missingParameters)); } else { /* * NOTE: Other configurators like the map-oriented one don't call into the listener, so do it the * hard way. */ validateParameters(mojoDescriptor, configuration, expressionEvaluator); } } } catch (ComponentConfigurationException e) { String message = "Unable to parse configuration of mojo " + mojoDescriptor.getId(); if (e.getFailedConfiguration() != null) { message += " for parameter " + e.getFailedConfiguration().getName(); } message += ": " + e.getMessage(); throw new PluginConfigurationException(mojoDescriptor.getPluginDescriptor(), message, e); } catch (ComponentLookupException e) { throw new PluginConfigurationException(mojoDescriptor.getPluginDescriptor(), "Unable to retrieve component configurator " + configuratorId + " for configuration of mojo " + mojoDescriptor.getId(), e); } catch (NoClassDefFoundError e) { ByteArrayOutputStream os = new ByteArrayOutputStream(1024); PrintStream ps = new PrintStream(os); ps.println("A required class was missing during configuration of mojo " + mojoDescriptor.getId() + ": " + e.getMessage()); pluginRealm.display(ps); throw new PluginConfigurationException(mojoDescriptor.getPluginDescriptor(), os.toString(), e); } catch (LinkageError e) { ByteArrayOutputStream os = new ByteArrayOutputStream(1024); PrintStream ps = new PrintStream(os); ps.println("An API incompatibility was encountered during configuration of mojo " + mojoDescriptor.getId() + ": " + e.getClass().getName() + ": " + e.getMessage()); pluginRealm.display(ps); throw new PluginConfigurationException(mojoDescriptor.getPluginDescriptor(), os.toString(), e); } finally { if (configurator != null) { try { container.release(configurator); } catch (ComponentLifecycleException e) { logger.debug("Failed to release mojo configurator - ignoring."); } } } } private void validateParameters(MojoDescriptor mojoDescriptor, PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator) throws ComponentConfigurationException, PluginParameterException { if (mojoDescriptor.getParameters() == null) { return; } List<Parameter> invalidParameters = new ArrayList<>(); for (Parameter parameter : mojoDescriptor.getParameters()) { if (!parameter.isRequired()) { continue; } Object value = null; PlexusConfiguration config = configuration.getChild(parameter.getName(), false); if (config != null) { String expression = config.getValue(null); try { value = expressionEvaluator.evaluate(expression); if (value == null) { value = config.getAttribute("default-value", null); } } catch (ExpressionEvaluationException e) { String msg = "Error evaluating the expression '" + expression + "' for configuration value '" + configuration.getName() + "'"; throw new ComponentConfigurationException(configuration, msg, e); } } if (value == null && (config == null || config.getChildCount() <= 0)) { invalidParameters.add(parameter); } } if (!invalidParameters.isEmpty()) { throw new PluginParameterException(mojoDescriptor, invalidParameters); } } public void releaseMojo(Object mojo, MojoExecution mojoExecution) { if (mojo != null) { try { container.release(mojo); } catch (ComponentLifecycleException e) { String goalExecId = mojoExecution.getGoal(); if (mojoExecution.getExecutionId() != null) { goalExecId += " {execution: " + mojoExecution.getExecutionId() + "}"; } logger.debug("Error releasing mojo for " + goalExecId, e); } } } public ExtensionRealmCache.CacheRecord setupExtensionsRealm(MavenProject project, Plugin plugin, RepositorySystemSession session) throws PluginManagerException { @SuppressWarnings("unchecked") Map<String, ExtensionRealmCache.CacheRecord> pluginRealms = (Map<String, ExtensionRealmCache.CacheRecord>) project .getContextValue(KEY_EXTENSIONS_REALMS); if (pluginRealms == null) { pluginRealms = new HashMap<>(); project.setContextValue(KEY_EXTENSIONS_REALMS, pluginRealms); } final String pluginKey = plugin.getId(); ExtensionRealmCache.CacheRecord extensionRecord = pluginRealms.get(pluginKey); if (extensionRecord != null) { return extensionRecord; } final List<RemoteRepository> repositories = project.getRemotePluginRepositories(); // resolve plugin version as necessary if (plugin.getVersion() == null) { PluginVersionRequest versionRequest = new DefaultPluginVersionRequest(plugin, session, repositories); try { plugin.setVersion(pluginVersionResolver.resolve(versionRequest).getVersion()); } catch (PluginVersionResolutionException e) { throw new PluginManagerException(plugin, e.getMessage(), e); } } // resolve plugin artifacts List<Artifact> artifacts; PluginArtifactsCache.Key cacheKey = pluginArtifactsCache.createKey(plugin, null, repositories, session); PluginArtifactsCache.CacheRecord recordArtifacts; try { recordArtifacts = pluginArtifactsCache.get(cacheKey); } catch (PluginResolutionException e) { throw new PluginManagerException(plugin, e.getMessage(), e); } if (recordArtifacts != null) { artifacts = recordArtifacts.artifacts; } else { try { artifacts = resolveExtensionArtifacts(plugin, repositories, session); recordArtifacts = pluginArtifactsCache.put(cacheKey, artifacts); } catch (PluginResolutionException e) { pluginArtifactsCache.put(cacheKey, e); pluginArtifactsCache.register(project, cacheKey, recordArtifacts); throw new PluginManagerException(plugin, e.getMessage(), e); } } pluginArtifactsCache.register(project, cacheKey, recordArtifacts); // create and cache extensions realms final ExtensionRealmCache.Key extensionKey = extensionRealmCache.createKey(artifacts); extensionRecord = extensionRealmCache.get(extensionKey); if (extensionRecord == null) { ClassRealm extensionRealm = classRealmManager.createExtensionRealm(plugin, toAetherArtifacts(artifacts)); // TODO figure out how to use the same PluginDescriptor when running mojos PluginDescriptor pluginDescriptor = null; if (plugin.isExtensions() && !artifacts.isEmpty()) { // ignore plugin descriptor parsing errors at this point // these errors will reported during calculation of project build execution plan try { pluginDescriptor = extractPluginDescriptor(artifacts.get(0), plugin); } catch (PluginDescriptorParsingException | InvalidPluginDescriptorException e) { // ignore, see above } } discoverPluginComponents(extensionRealm, plugin, pluginDescriptor); ExtensionDescriptor extensionDescriptor = null; Artifact extensionArtifact = artifacts.get(0); try { extensionDescriptor = extensionDescriptorBuilder.build(extensionArtifact.getFile()); } catch (IOException e) { String message = "Invalid extension descriptor for " + plugin.getId() + ": " + e.getMessage(); if (logger.isDebugEnabled()) { logger.error(message, e); } else { logger.error(message); } } extensionRecord = extensionRealmCache.put(extensionKey, extensionRealm, extensionDescriptor, artifacts); } extensionRealmCache.register(project, extensionKey, extensionRecord); pluginRealms.put(pluginKey, extensionRecord); return extensionRecord; } private List<Artifact> resolveExtensionArtifacts(Plugin extensionPlugin, List<RemoteRepository> repositories, RepositorySystemSession session) throws PluginResolutionException { DependencyNode root = pluginDependenciesResolver.resolve(extensionPlugin, null, null, repositories, session); PreorderNodeListGenerator nlg = new PreorderNodeListGenerator(); root.accept(nlg); return toMavenArtifacts(root, nlg); } }