/* * $Id$ * * SARL is an general-purpose agent programming language. * More details on http://www.sarl.io * * Copyright (C) 2014-2017 the original authors or authors. * * Licensed 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. */ package io.sarl.maven.compiler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Set; import java.util.TreeMap; import com.google.common.base.Strings; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.artifact.resolver.ArtifactResolutionException; import org.apache.maven.artifact.resolver.ArtifactResolutionRequest; import org.apache.maven.artifact.resolver.ArtifactResolutionResult; import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException; import org.apache.maven.artifact.resolver.ResolutionErrorHandler; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Dependency; import org.apache.maven.model.Plugin; import org.apache.maven.plugin.BuildPluginManager; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.PluginConfigurationException; import org.apache.maven.plugin.PluginManagerException; import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.plugin.logging.Log; import org.apache.maven.repository.RepositorySystem; import org.arakhne.afc.vmutil.locale.Locale; /** This class permits to support the incompatible Maven API * from the same Mojo code (says 3.0 and 3.1 APIs). * * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ class MavenHelper { private Map<String, Dependency> pluginDependencies; private final MavenSession session; private final BuildPluginManager buildPluginManager; private final Log log; private final Method getRepositorySessionMethod; private final Method loadPluginMethod; private final RepositorySystem repositorySystem; private final ResolutionErrorHandler resolutionErrorHandler; /** * @param session - the Maven session. * @param buildPluginManager - the Maven build plugin manager. * @param repositorySystem - the Repository system. * @param resolutionErrorHandler - the error handler during artifact resolution. * @param log - the log for the caller. * @throws MojoExecutionException if cannot get the accessors. */ MavenHelper(MavenSession session, BuildPluginManager buildPluginManager, RepositorySystem repositorySystem, ResolutionErrorHandler resolutionErrorHandler, Log log) throws MojoExecutionException { this.session = session; this.buildPluginManager = buildPluginManager; this.log = log; this.repositorySystem = repositorySystem; this.resolutionErrorHandler = resolutionErrorHandler; Method method; method = null; for (final Method m : this.session.getClass().getDeclaredMethods()) { if ("getRepositorySession".equals(m.getName())) { //$NON-NLS-1$ method = m; break; } } if (method == null) { throw new MojoExecutionException(Locale.getString(MavenHelper.class, "UNSUPPORTED_MAVEN_API"), //$NON-NLS-1$ new NoSuchMethodError("getRepositorySystem")); //$NON-NLS-1$ } this.getRepositorySessionMethod = method; method = null; for (final Method m : this.buildPluginManager.getClass().getDeclaredMethods()) { if ("loadPlugin".equals(m.getName())) { //$NON-NLS-1$ method = m; break; } } if (method == null) { throw new MojoExecutionException(Locale.getString(MavenHelper.class, "UNSUPPORTED_MAVEN_API"), //$NON-NLS-1$ new NoSuchMethodError("loadPlugin")); //$NON-NLS-1$ } this.loadPluginMethod = method; } /** Replies the current Maven session. * * @return the session. */ public MavenSession getSession() { return this.session; } /** Replies the manager of the build plugins. * * @return the manager of the build plugins. */ public BuildPluginManager getBuildPluginManager() { return this.buildPluginManager; } /** Extract the value from the hard-coded configuration. * * @param key - the key of the configuration entry. * @return the value. * @throws MojoExecutionException on error. */ public String getConfig(String key) throws MojoExecutionException { ResourceBundle resource = null; try { resource = ResourceBundle.getBundle( "io/sarl/maven/compiler/config", //$NON-NLS-1$ java.util.Locale.getDefault(), MavenHelper.class.getClassLoader()); } catch (MissingResourceException e) { throw new MojoExecutionException(e.getLocalizedMessage(), e); } String value = resource.getString(key); if (value == null || value.isEmpty()) { value = Strings.nullToEmpty(value); this.log.warn(Locale.getString(MavenHelper.class, "NO_CONFIGURATION_ENTRY", key)); //$NON-NLS-1$ } return value; } /** Load the given plugin. * * @param plugin - the plugin to load. * @return the descriptor of the plugin. * @throws MojoExecutionException if something bad append. */ public PluginDescriptor loadPlugin(Plugin plugin) throws MojoExecutionException { try { final Object repositorySessionObject = this.getRepositorySessionMethod.invoke(this.session); return (PluginDescriptor) this.loadPluginMethod.invoke( this.buildPluginManager, plugin, Collections.EMPTY_LIST, repositorySessionObject); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new MojoExecutionException(e.getLocalizedMessage(), e); } } /** Execute the given mojo. * * @param mojo - the mojo to execute. * @throws MojoExecutionException if the mojo cannot be run properly. * @throws MojoFailureException if the build failed. */ public void executeMojo(MojoExecution mojo) throws MojoExecutionException, MojoFailureException { try { this.buildPluginManager.executeMojo(this.session, mojo); } catch (PluginConfigurationException | PluginManagerException e) { throw new MojoFailureException(e.getLocalizedMessage(), e); } } /** Convert an artifact to a dependency. * * @param artifact - the artifact to convert. * @return the result of the conversion. */ @SuppressWarnings("static-method") public Dependency toDependency(Artifact artifact) { final Dependency result = new Dependency(); result.setArtifactId(artifact.getArtifactId()); result.setClassifier(artifact.getClassifier()); result.setGroupId(artifact.getGroupId()); result.setOptional(artifact.isOptional()); result.setScope(artifact.getScope()); result.setType(artifact.getType()); result.setVersion(artifact.getVersion()); return result; } /** Build the map of dependencies for the current plugin. * * @return the artifact. * @throws MojoExecutionException if the current plugin cannot be determined. */ public synchronized Map<String, Dependency> getPluginDependencies() throws MojoExecutionException { if (this.pluginDependencies == null) { final String groupId = getConfig("plugin.groupId"); //$NON-NLS-1$ final String artifactId = getConfig("plugin.artifactId"); //$NON-NLS-1$ final String pluginArtifactKey = ArtifactUtils.versionlessKey(groupId, artifactId); final Set<Artifact> dependencies = resolveDependencies(pluginArtifactKey, true); final Map<String, Dependency> deps = new TreeMap<>(); for (final Artifact artifact : dependencies) { final Dependency dep = toDependency(artifact); deps.put(ArtifactUtils.versionlessKey(artifact), dep); } this.pluginDependencies = deps; } return this.pluginDependencies; } /** Replies the dependencies for the given artifact. * * @param artifactId - the artifact identifier. * @param plugins indicates if the map of the plugin artifacts must be explore (if true) or the dependency * artifacts (if false). * @return the dependencies. * @throws MojoExecutionException if the resolution cannot be done. */ public Set<Artifact> resolveDependencies(String artifactId, boolean plugins) throws MojoExecutionException { final Artifact pluginArtifact; if (plugins) { pluginArtifact = getSession().getCurrentProject().getPluginArtifactMap().get(artifactId); } else { pluginArtifact = getSession().getCurrentProject().getArtifactMap().get(artifactId); } final ArtifactResolutionRequest request = new ArtifactResolutionRequest(); request.setResolveRoot(false); request.setResolveTransitively(true); request.setLocalRepository(getSession().getLocalRepository()); request.setOffline(getSession().isOffline()); request.setForceUpdate(getSession().getRequest().isUpdateSnapshots()); request.setServers(getSession().getRequest().getServers()); request.setMirrors(getSession().getRequest().getMirrors()); request.setProxies(getSession().getRequest().getProxies()); request.setArtifact(pluginArtifact); final ArtifactResolutionResult result = this.repositorySystem.resolve(request); try { this.resolutionErrorHandler.throwErrors(request, result); } catch (MultipleArtifactsNotFoundException e) { final Collection<Artifact> missing = new HashSet<>(e.getMissingArtifacts()); if (!missing.isEmpty()) { throw new MojoExecutionException(e.getLocalizedMessage(), e); } } catch (ArtifactResolutionException e) { throw new MojoExecutionException(e.getLocalizedMessage(), e); } return result.getArtifacts(); } /** Replies the version of the given plugin that is specified in the POM of the * plugin in which this mojo is located. * * @param groupId - the identifier of the group. * @param artifactId - thidentifier of the artifact. * @return the version, never <code>null</code> * @throws MojoExecutionException if the plugin was not found. */ public String getPluginDependencyVersion(String groupId, String artifactId) throws MojoExecutionException { final Map<String, Dependency> deps = getPluginDependencies(); final String key = ArtifactUtils.versionlessKey(groupId, artifactId); this.log.debug("COMPONENT DEPENDENCIES(getPluginVersionFromDependencies):"); //$NON-NLS-1$ this.log.debug(deps.toString()); final Dependency dep = deps.get(key); if (dep != null) { final String version = dep.getVersion(); if (version != null && !version.isEmpty()) { return version; } throw new MojoExecutionException(Locale.getString(MavenHelper.class, "UNKNOWN_PLUGIN_VERSION", key)); //$NON-NLS-1$ } throw new MojoExecutionException(Locale.getString(MavenHelper.class, "PLUGIN_NOT_FOUND_IN_DEPS", key, deps)); //$NON-NLS-1$ } }