/******************************************************************************* * Copyright (c) 2015 Takari, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Anton Tanasenko - initial API and implementation *******************************************************************************/ package org.eclipse.m2e.editor.xml.internal.mojo; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableMap; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.ui.PlatformUI; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.apache.maven.DefaultMaven; import org.apache.maven.model.Plugin; import org.apache.maven.model.building.ModelSource; import org.apache.maven.model.building.UrlModelSource; import org.apache.maven.plugin.BuildPluginManager; import org.apache.maven.plugin.MavenPluginManager; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuilder; import org.apache.maven.project.ProjectBuildingException; import org.eclipse.m2e.core.MavenPlugin; import org.eclipse.m2e.core.embedder.ArtifactKey; import org.eclipse.m2e.core.embedder.ICallable; import org.eclipse.m2e.core.embedder.IMavenExecutionContext; import org.eclipse.m2e.core.internal.IMavenConstants; import org.eclipse.m2e.core.internal.Messages; import org.eclipse.m2e.core.internal.embedder.MavenExecutionContext; import org.eclipse.m2e.core.internal.embedder.MavenImpl; import org.eclipse.m2e.editor.xml.MvnIndexPlugin; import org.eclipse.m2e.editor.xml.mojo.IMojoParameterMetadata; import org.eclipse.m2e.editor.xml.mojo.IMojoParameterMetadataProvider; import org.eclipse.m2e.editor.xml.mojo.MojoParameter; import org.eclipse.m2e.editor.xml.mojo.PlexusConfigHelper; /** * @author atanasenko */ @SuppressWarnings("restriction") public class MojoParameterMetadataProvider implements IMojoParameterMetadataProvider { private static final Logger log = LoggerFactory.getLogger(MojoParameterMetadataProvider.class); private static final Cache<String, MojoParameter> cache = CacheBuilder.newBuilder().maximumSize(100).softValues() .build(); protected final MavenImpl maven; public MojoParameterMetadataProvider() { maven = (MavenImpl) MavenPlugin.getMaven(); } @Deprecated public MojoParameter getClassConfiguration(ArtifactKey pluginKey, String className, IProgressMonitor monitor) throws CoreException { return getClassConfiguration(pluginKey, className); } @Deprecated public MojoParameter getMojoConfiguration(ArtifactKey pluginKey, Collection<String> mojos, IProgressMonitor monitor) throws CoreException { return getMojoConfiguration(pluginKey, mojos); } @Deprecated public MojoParameter getMojoConfiguration(ArtifactKey pluginKey, IProgressMonitor monitor) throws CoreException { return getMojoConfiguration(pluginKey); } @Deprecated public MojoParameter getMojoConfiguration(ArtifactKey pluginKey, String mojo, IProgressMonitor monitor) throws CoreException { return getMojoConfiguration(pluginKey, mojo); } public MojoParameter getClassConfiguration(final ArtifactKey pluginKey, final String className) throws CoreException { try { String key = pluginKey.toPortableString() + "/" + className; return cache.get(key, new Callable<MojoParameter>() { public MojoParameter call() throws Exception { return execute(pluginKey, new ICallable<MojoParameter>() { public MojoParameter call(IMavenExecutionContext context, IProgressMonitor monitor) throws CoreException { PluginDescriptor pd = getPluginDescriptor(pluginKey, context, monitor); List<MojoParameter> parameters = null; if(pd != null) { Class<?> clazz; try { clazz = pd.getClassRealm().loadClass(className); } catch(ClassNotFoundException ex) { return null; } parameters = new PlexusConfigHelper().loadParameters(pd.getClassRealm(), clazz, monitor); } return new MojoParameter("", className, parameters); //$NON-NLS-1$ } }); } }); } catch(ExecutionException e) { Throwable t = e.getCause(); if(t instanceof CoreException) { throw (CoreException) t; } if(t instanceof RuntimeException) { throw (RuntimeException) t; } throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, e.getMessage(), e)); } } public MojoParameter getMojoConfiguration(ArtifactKey pluginKey, final Collection<String> mojos) throws CoreException { List<MojoParameter> params = new ArrayList<>(); Set<String> collected = new HashSet<>(); for(String mojo : mojos) { MojoParameter md = getMojoConfiguration(pluginKey, mojo); for(MojoParameter p : md.getNestedParameters()) { if(!collected.add(p.getName())) continue; params.add(p); } } return new MojoParameter("", "", params); //$NON-NLS-1$ //$NON-NLS-2$ } public MojoParameter getMojoConfiguration(ArtifactKey pluginKey) throws CoreException { return getMojoConfiguration(pluginKey, "*"); //$NON-NLS-1$ } public MojoParameter getMojoConfiguration(final ArtifactKey pluginKey, final String mojo) throws CoreException { MojoParameter predefParameters = getPredefined(pluginKey); if(predefParameters != null) { return predefParameters; } String key = pluginKey.toPortableString() + "/mojo/" + (mojo == null ? "*" : mojo); //$NON-NLS-1$ //$NON-NLS-2$ try { return cache.get(key, new Callable<MojoParameter>() { public MojoParameter call() throws Exception { return execute(pluginKey, new ICallable<MojoParameter>() { public MojoParameter call(IMavenExecutionContext context, IProgressMonitor monitor) throws CoreException { PluginDescriptor pd = getPluginDescriptor(pluginKey, context, monitor); List<MojoParameter> parameters = null; if(pd != null) { parameters = loadMojoParameters(pd, mojo, monitor); } return new MojoParameter("", mojo, parameters); //$NON-NLS-1$ } }); } }); } catch(ExecutionException e) { Throwable t = e.getCause(); if(t instanceof CoreException) { throw (CoreException) t; } if(t instanceof RuntimeException) { throw (RuntimeException) t; } throw new CoreException(new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, e.getMessage(), e)); } } List<MojoParameter> loadMojoParameters(PluginDescriptor desc, String goal, IProgressMonitor monitor) throws CoreException { PlexusConfigHelper helper = new PlexusConfigHelper(); if(goal.equals("*")) { //$NON-NLS-1$ List<MojoParameter> parameters = new ArrayList<>(); Set<String> collected = new HashSet<>(); for(MojoDescriptor mojo : desc.getMojos()) { for(MojoParameter p : loadMojoParameters(desc, mojo, helper, monitor)) { if(collected.add(p.getName())) { parameters.add(p); } } } return parameters; } return loadMojoParameters(desc, desc.getMojo(goal), helper, monitor); } private MojoParameter getPredefined(ArtifactKey pluginKey) { return PREDEF.get(pluginKey.getGroupId() + ":" + pluginKey.getArtifactId() + ":" + pluginKey.getVersion()); } <T> T execute(final ArtifactKey pluginKey, final ICallable<T> callable) throws CoreException { final Object[] result = new Object[1]; final CoreException[] innerException = new CoreException[1]; try { PlatformUI.getWorkbench().getActiveWorkbenchWindow().run(true, true, new IRunnableWithProgress() { public void run(IProgressMonitor monitor) { monitor.beginTask(org.eclipse.m2e.editor.xml.internal.Messages.PomTemplateContext_resolvingPlugin, 100); try { MavenExecutionContext context = maven.createExecutionContext(); context.getExecutionRequest().setCacheTransferError(false); T res = context.execute(new ICallable<T>() { public T call(IMavenExecutionContext context, IProgressMonitor monitor) throws CoreException { MavenProject mp = getProject(context); if(mp != null) { return context.execute(mp, callable, monitor); } return null; } }, monitor); if(monitor.isCanceled()) return; result[0] = res; } catch(CoreException ex) { if(monitor.isCanceled()) return; innerException[0] = ex; } } }); } catch(InvocationTargetException | InterruptedException ex) { throw new CoreException(new Status(IStatus.ERROR, MvnIndexPlugin.PLUGIN_ID, ex.getMessage(), ex)); } if(innerException[0] != null) { throw innerException[0]; } @SuppressWarnings("unchecked") T res = (T) result[0]; return res; } MavenProject getProject(IMavenExecutionContext context) { ModelSource modelSource = new UrlModelSource(DefaultMaven.class.getResource("project/standalone.xml")); //$NON-NLS-1$ try { return lookup(ProjectBuilder.class).build(modelSource, context.newProjectBuildingRequest()).getProject(); } catch(ProjectBuildingException | CoreException ex) { log.warn(ex.getMessage()); return null; } } PluginDescriptor getPluginDescriptor(ArtifactKey pluginKey, IMavenExecutionContext context, IProgressMonitor monitor) { PluginDescriptor desc; Plugin plugin = new Plugin(); plugin.setGroupId(pluginKey.getGroupId()); plugin.setArtifactId(pluginKey.getArtifactId()); plugin.setVersion(pluginKey.getVersion()); List<RemoteRepository> remoteRepos = context.getSession().getCurrentProject().getRemotePluginRepositories(); try { desc = lookup(MavenPluginManager.class).getPluginDescriptor(plugin, remoteRepos, context.getRepositorySession()); lookup(BuildPluginManager.class).getPluginRealm(context.getSession(), desc); return desc; } catch(Exception ex) { log.warn(ex.getMessage()); return null; } } <T> T lookup(Class<T> clazz) throws CoreException { try { return maven.getPlexusContainer().lookup(clazz); } catch(ComponentLookupException ex) { throw new CoreException( new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, Messages.MavenImpl_error_lookup, ex)); } } List<MojoParameter> loadMojoParameters(PluginDescriptor desc, MojoDescriptor mojo, PlexusConfigHelper helper, IProgressMonitor monitor) throws CoreException { IMojoParameterMetadata metadata = null; String mojoConfigurator = mojo.getComponentConfigurator(); if(mojoConfigurator != null) { metadata = readMojoParameterMetadata(mojoConfigurator); } if(metadata == null) { metadata = new DefaultMojoParameterMetadata(); } return metadata.loadMojoParameters(desc, mojo, helper, monitor); } public static final String EXTENSION_MOJO_PARAMETER_METADATA = MvnIndexPlugin.PLUGIN_ID + ".mojoParameterMetadata"; //$NON-NLS-1$ private static IMojoParameterMetadata readMojoParameterMetadata(String mojoConfigurator) { IExtensionRegistry registry = Platform.getExtensionRegistry(); IExtensionPoint mappingsExtensionPoint = registry.getExtensionPoint(EXTENSION_MOJO_PARAMETER_METADATA); if(mappingsExtensionPoint != null) { IExtension[] mappingsExtensions = mappingsExtensionPoint.getExtensions(); for(IExtension extension : mappingsExtensions) { IConfigurationElement[] elements = extension.getConfigurationElements(); for(IConfigurationElement element : elements) { if(element.getName().equals("mojoParameterMetadata") //$NON-NLS-1$ && mojoConfigurator.equals(element.getAttribute("configurator"))) { //$NON-NLS-1$ try { return (IMojoParameterMetadata) element.createExecutableExtension("class"); //$NON-NLS-1$ } catch(CoreException ex) { log.error(ex.getMessage(), ex); } } } } } return null; } private static final Map<String, MojoParameter> PREDEF; static { // @formatter:off PREDEF = ImmutableMap.<String, MojoParameter>of( "org.eclipse.m2e:lifecycle-mapping:1.0.0", new MojoParameter("", "", Collections.singletonList( new MojoParameter("lifecycleMappingMetadata", "LifecycleMappingMetadata", Collections.singletonList( new MojoParameter("pluginExecutions", "List<PluginExecution>", Collections.singletonList( new MojoParameter("pluginExecution", "PluginExecution", Arrays.asList( new MojoParameter("pluginExecutionFilter", "PluginExecutionFilter", Arrays.asList( new MojoParameter("groupId", "String"), new MojoParameter("artifactId", "String"), new MojoParameter("versionRange", "String"), new MojoParameter("goals", "List<String>", Collections.singletonList( new MojoParameter("goal", "String").multiple() )) )), new MojoParameter("action", "Action", Arrays.asList( new MojoParameter("ignore", "void"), new MojoParameter("execute", "Execute", Arrays.asList( new MojoParameter("runOnIncremental", "boolean"), new MojoParameter("runOnConfiguration", "boolean") )) )) )).multiple() )) )) )) ); // @formatter:on } }