Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Tanasenko2015-05-24 12:16:57 +0000
committerAnton Tanasenko2015-05-25 16:19:13 +0000
commit3e7111c55ca2b5c5ef62d4655dcbac7723ae842d (patch)
tree9f0986c404b5612aa429ebacb6d1c98d1aeddeaa
parentd9a3f3c9d6954372ba5b7899cfcdee45fa0b43da (diff)
downloadm2e-core-3e7111c55ca2b5c5ef62d4655dcbac7723ae842d.tar.gz
m2e-core-3e7111c55ca2b5c5ef62d4655dcbac7723ae842d.tar.xz
m2e-core-3e7111c55ca2b5c5ef62d4655dcbac7723ae842d.zip
468133 Extension point for pom mojo configuration content assist
Change-Id: Ifd2e3bad27314880e98998a97ed7abd26d648d30 Signed-off-by: Anton Tanasenko <atg.sleepless@gmail.com>
-rw-r--r--org.eclipse.m2e.editor.xml/META-INF/MANIFEST.MF1
-rw-r--r--org.eclipse.m2e.editor.xml/plugin.properties1
-rw-r--r--org.eclipse.m2e.editor.xml/plugin.xml1
-rw-r--r--org.eclipse.m2e.editor.xml/schema/.gitignore0
-rw-r--r--org.eclipse.m2e.editor.xml/schema/mojoParameterMetadata.exsd121
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContext.java22
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/mojo/DefaultMojoParameterMetadata.java87
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/mojo/MojoParameterMetadataProvider.java686
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/IMojoParameterMetadata.java34
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/IMojoParameterMetadataProvider.java53
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/MojoParameter.java (renamed from org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/mojo/MojoParameter.java)16
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/PlexusConfigHelper.java460
12 files changed, 916 insertions, 566 deletions
diff --git a/org.eclipse.m2e.editor.xml/META-INF/MANIFEST.MF b/org.eclipse.m2e.editor.xml/META-INF/MANIFEST.MF
index 1f18d4c3..b2c5d70c 100644
--- a/org.eclipse.m2e.editor.xml/META-INF/MANIFEST.MF
+++ b/org.eclipse.m2e.editor.xml/META-INF/MANIFEST.MF
@@ -27,6 +27,7 @@ Export-Package: org.eclipse.m2e.editor.xml;x-internal:=true,
org.eclipse.m2e.editor.xml.internal;x-internal:=true,
org.eclipse.m2e.editor.xml.internal.lifecycle;x-internal:=true,
org.eclipse.m2e.editor.xml.internal.mojo;x-internal:=true,
+ org.eclipse.m2e.editor.xml.mojo;x-internal:=true,
org.eclipse.m2e.editor.xml.preferences;x-internal:=true
Bundle-ClassPath: .
Bundle-Vendor: %Bundle-Vendor
diff --git a/org.eclipse.m2e.editor.xml/plugin.properties b/org.eclipse.m2e.editor.xml/plugin.properties
new file mode 100644
index 00000000..1a903c03
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/plugin.properties
@@ -0,0 +1 @@
+extension-point.mojoParameterMetadata.name=Mojo Parameter Metadata
diff --git a/org.eclipse.m2e.editor.xml/plugin.xml b/org.eclipse.m2e.editor.xml/plugin.xml
index 17ecab89..bb01872b 100644
--- a/org.eclipse.m2e.editor.xml/plugin.xml
+++ b/org.eclipse.m2e.editor.xml/plugin.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
+ <extension-point id="mojoParameterMetadata" name="%extension-point.mojoParameterMetadata.name" schema="schema/mojoParameterMetadata.exsd"/>
<extension point="org.eclipse.wst.sse.ui.editorConfiguration">
<sourceViewerConfiguration
diff --git a/org.eclipse.m2e.editor.xml/schema/.gitignore b/org.eclipse.m2e.editor.xml/schema/.gitignore
deleted file mode 100644
index e69de29b..00000000
--- a/org.eclipse.m2e.editor.xml/schema/.gitignore
+++ /dev/null
diff --git a/org.eclipse.m2e.editor.xml/schema/mojoParameterMetadata.exsd b/org.eclipse.m2e.editor.xml/schema/mojoParameterMetadata.exsd
new file mode 100644
index 00000000..f10eba03
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/schema/mojoParameterMetadata.exsd
@@ -0,0 +1,121 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.m2e.editor.xml" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="org.eclipse.m2e.editor.xml" id="mojoParameterMetadata" name="%extension-point.mojoParameterMetadata.name"/>
+ </appInfo>
+ <documentation>
+ Mojo parameter metadata sources provide plugin configuration options that mirror the corresponding component configurator
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appInfo>
+ <meta.element />
+ </appInfo>
+ </annotation>
+ <complexType>
+ <sequence minOccurs="1" maxOccurs="unbounded">
+ <element ref="mojoParameterMetadata"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="mojoParameterMetadata">
+ <complexType>
+ <attribute name="configurator" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appInfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.m2e.editor.xml.mojo.IMojoParameterMetadata"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="since"/>
+ </appInfo>
+ <documentation>
+ 1.6
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="examples"/>
+ </appInfo>
+ <documentation>
+ [Enter extension point usage example here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiinfo"/>
+ </appInfo>
+ <documentation>
+ [Enter API information here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="implementation"/>
+ </appInfo>
+ <documentation>
+ [Enter information about supplied implementation of this extension point.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="copyright"/>
+ </appInfo>
+ <documentation>
+ 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
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContext.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContext.java
index 891bb878..14ff2315 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContext.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContext.java
@@ -54,14 +54,16 @@ import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.project.MavenProject;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
import org.eclipse.m2e.core.ui.internal.M2EUIPluginActivator;
import org.eclipse.m2e.core.ui.internal.search.util.ArtifactInfo;
import org.eclipse.m2e.core.ui.internal.search.util.Packaging;
import org.eclipse.m2e.core.ui.internal.search.util.SearchEngine;
import org.eclipse.m2e.editor.xml.internal.Messages;
import org.eclipse.m2e.editor.xml.internal.XmlUtils;
-import org.eclipse.m2e.editor.xml.internal.mojo.MojoParameter;
import org.eclipse.m2e.editor.xml.internal.mojo.MojoParameterMetadataProvider;
+import org.eclipse.m2e.editor.xml.mojo.IMojoParameterMetadataProvider;
+import org.eclipse.m2e.editor.xml.mojo.MojoParameter;
/**
@@ -115,8 +117,8 @@ public enum PomTemplateContext {
}
@Override
- protected void addTemplates(MavenProject project, IProject eclipseprj, Collection<Template> proposals, Node node,
- String prefix) throws CoreException {
+ protected void addTemplates(final MavenProject project, IProject eclipseprj, Collection<Template> proposals,
+ Node node, String prefix) throws CoreException {
// find configuration ancestor
List<String> pathElements = new ArrayList<String>();
@@ -181,16 +183,12 @@ public enum PomTemplateContext {
}
}
- Plugin plugin = new Plugin();
- plugin.setGroupId(groupId);
- plugin.setArtifactId(artifactId);
- plugin.setVersion(version);
-
+ final ArtifactKey pluginKey = new ArtifactKey(groupId, artifactId, version, null);
final String fConfigImpl = configImpl;
final MojoParameter[] parameterMetadata = new MojoParameter[1];
final CoreException[] innerException = new CoreException[1];
- final MojoParameterMetadataProvider prov = new MojoParameterMetadataProvider(project, plugin);
+ final IMojoParameterMetadataProvider prov = new MojoParameterMetadataProvider();
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().run(true, true, new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) {
@@ -198,11 +196,11 @@ public enum PomTemplateContext {
try {
MojoParameter parameter;
if(fConfigImpl != null) {
- parameter = prov.getParameterRoot(fConfigImpl, monitor);
+ parameter = prov.getClassConfiguration(pluginKey, fConfigImpl, monitor);
} else if(usedMojos.isEmpty()) {
- parameter = prov.getMojoParameterRoot(monitor);
+ parameter = prov.getMojoConfiguration(pluginKey, monitor);
} else {
- parameter = prov.getMojoParameterRoot(usedMojos, monitor);
+ parameter = prov.getMojoConfiguration(pluginKey, usedMojos, monitor);
}
if(monitor.isCanceled())
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/mojo/DefaultMojoParameterMetadata.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/mojo/DefaultMojoParameterMetadata.java
new file mode 100644
index 00000000..fb229b37
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/mojo/DefaultMojoParameterMetadata.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * 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.Type;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.Parameter;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+
+import org.eclipse.m2e.editor.xml.mojo.IMojoParameterMetadata;
+import org.eclipse.m2e.editor.xml.mojo.MojoParameter;
+import org.eclipse.m2e.editor.xml.mojo.PlexusConfigHelper;
+
+
+/**
+ * DefaultMojoParameterMetadataSource
+ *
+ * @author sleepless
+ */
+public class DefaultMojoParameterMetadata implements IMojoParameterMetadata {
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ public List<MojoParameter> loadMojoParameters(PluginDescriptor desc, MojoDescriptor mojo, PlexusConfigHelper helper,
+ IProgressMonitor monitor) throws CoreException {
+
+ if(monitor.isCanceled()) {
+ return Collections.emptyList();
+ }
+ Class<?> clazz;
+ try {
+ clazz = mojo.getImplementationClass();
+ if(clazz == null) {
+ clazz = desc.getClassRealm().loadClass(mojo.getImplementation());
+ }
+ } catch(ClassNotFoundException | TypeNotPresentException ex) {
+ log.warn(ex.getMessage());
+ return Collections.emptyList();
+ }
+
+ List<Parameter> ps = mojo.getParameters();
+ Map<String, Type> properties = helper.getClassProperties(clazz);
+
+ List<MojoParameter> parameters = new ArrayList<>();
+
+ if(ps != null) {
+ for(Parameter p : ps) {
+ if(monitor.isCanceled()) {
+ return Collections.emptyList();
+ }
+ if(!p.isEditable()) {
+ continue;
+ }
+
+ Type type = properties.get(p.getName());
+ if(type == null) {
+ continue;
+ }
+
+ helper.addParameter(desc.getClassRealm(), clazz, type, p.getName(), p.getAlias(), parameters, p.isRequired(),
+ p.getExpression(), p.getDescription(), p.getDefaultValue(), monitor);
+ }
+ }
+
+ return parameters;
+ }
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/mojo/MojoParameterMetadataProvider.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/mojo/MojoParameterMetadataProvider.java
index 07f6b4a4..d3a6b7b1 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/mojo/MojoParameterMetadataProvider.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/mojo/MojoParameterMetadataProvider.java
@@ -11,39 +11,33 @@
package org.eclipse.m2e.editor.xml.internal.mojo;
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.net.URI;
-import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Properties;
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 com.google.common.collect.ImmutableSet;
-import com.google.common.reflect.ClassPath;
-import com.google.common.reflect.ClassPath.ClassInfo;
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.codehaus.plexus.component.repository.exception.ComponentLookupException;
@@ -55,96 +49,91 @@ 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.Parameter;
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 {
+public class MojoParameterMetadataProvider implements IMojoParameterMetadataProvider {
private static final Logger log = LoggerFactory.getLogger(MojoParameterMetadataProvider.class);
- private final MavenProject project;
-
- private final Plugin plugin;
+ private static final Cache<String, MojoParameter> cache = CacheBuilder.newBuilder().maximumSize(100).softValues()
+ .build();
protected final MavenImpl maven;
- private final Map<String, List<MojoParameter>> parameters;
-
- public MojoParameterMetadataProvider(MavenProject project, Plugin plugin) {
- this.project = project;
- this.plugin = plugin;
+ public MojoParameterMetadataProvider() {
maven = (MavenImpl) MavenPlugin.getMaven();
- parameters = new HashMap<>();
}
- public MojoParameter getParameterRoot(final String className, IProgressMonitor monitor) throws CoreException {
-
- List<MojoParameter> plist = parameters.get(className);
- if(plist == null) {
- plist = new ArrayList<>();
- this.parameters.put(className, plist);
- final List<MojoParameter> parameters = plist;
-
- execute(new ICallable<Void>() {
- public Void call(IMavenExecutionContext context, IProgressMonitor monitor) throws CoreException {
- PluginDescriptor pd = getPluginDescriptor(context, monitor);
+ public MojoParameter getClassConfiguration(final ArtifactKey pluginKey, final String className,
+ final IProgressMonitor monitor) throws CoreException {
- if(pd != null) {
- Class<?> clazz;
- try {
- clazz = pd.getClassRealm().loadClass(className);
- } catch(ClassNotFoundException ex) {
+ 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);
+
+ if(pd != null) {
+ Class<?> clazz;
+ try {
+ clazz = pd.getClassRealm().loadClass(className);
+ } catch(ClassNotFoundException ex) {
+ return null;
+ }
+
+ return new MojoParameter("", className, //$NON-NLS-1$
+ new PlexusConfigHelper().loadParameters(pd.getClassRealm(), clazz, monitor));
+ }
return null;
}
-
- loadParameters(pd, clazz, parameters, monitor);
- }
- return null;
+ }, monitor);
}
- }, monitor);
- }
-
- return new MojoParameter("", className, plist); //$NON-NLS-1$
- }
-
- protected List<MojoParameter> getParameters(PluginDescriptor desc, final Class<?> clazz, IProgressMonitor monitor)
- throws CoreException {
-
- String key = clazz.getName();
- List<MojoParameter> plist = parameters.get(key);
+ });
- if(plist == null) {
- plist = new ArrayList<>();
- this.parameters.put(key, plist);
-
- loadParameters(desc, clazz, plist, monitor);
+ } 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));
}
-
- return plist;
}
- public MojoParameter getMojoParameterRoot(final Collection<String> mojos, IProgressMonitor monitor)
- throws CoreException {
+ public MojoParameter getMojoConfiguration(ArtifactKey pluginKey, final Collection<String> mojos,
+ IProgressMonitor monitor) throws CoreException {
List<MojoParameter> params = new ArrayList<>();
Set<String> collected = new HashSet<>();
for(String mojo : mojos) {
- MojoParameter md = getMojoParameterRoot(mojo, monitor);
+ MojoParameter md = getMojoConfiguration(pluginKey, mojo, monitor);
for(MojoParameter p : md.getNestedParameters()) {
if(!collected.add(p.getName()))
continue;
@@ -154,50 +143,78 @@ public class MojoParameterMetadataProvider {
return new MojoParameter("", "", params); //$NON-NLS-1$ //$NON-NLS-2$
}
- public MojoParameter getMojoParameterRoot(IProgressMonitor monitor) throws CoreException {
- return getMojoParameterRoot("*", monitor); //$NON-NLS-1$
+ public MojoParameter getMojoConfiguration(ArtifactKey pluginKey, IProgressMonitor monitor) throws CoreException {
+ return getMojoConfiguration(pluginKey, "*", monitor); //$NON-NLS-1$
}
- public MojoParameter getMojoParameterRoot(final String mojo, IProgressMonitor monitor) throws CoreException {
+ public MojoParameter getMojoConfiguration(final ArtifactKey pluginKey, final String mojo,
+ final IProgressMonitor monitor) throws CoreException {
- MojoParameter predefParameters = getPredefined();
+ MojoParameter predefParameters = getPredefined(pluginKey);
if(predefParameters != null) {
return predefParameters;
}
- String key = "mojo:" + (mojo == null ? "*" : mojo); //$NON-NLS-1$ //$NON-NLS-2$
+ String key = pluginKey.toPortableString() + "/mojo/" + (mojo == null ? "*" : mojo); //$NON-NLS-1$ //$NON-NLS-2$
- List<MojoParameter> plist = parameters.get(key);
+ 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);
+ if(pd != null) {
+ return new MojoParameter("", mojo, loadMojoParameters(pd, mojo, monitor)); //$NON-NLS-1$
+ }
+ return null;
+ }
+ }, monitor);
+ }
+ });
- if(plist == null) {
+ } 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 {
- final List<MojoParameter> parameters = new ArrayList<>();
- plist = parameters;
- this.parameters.put(key, plist);
+ PlexusConfigHelper helper = new PlexusConfigHelper();
- execute(new ICallable<Void>() {
- public Void call(IMavenExecutionContext context, IProgressMonitor monitor) throws CoreException {
- PluginDescriptor pd = getPluginDescriptor(context, monitor);
- if(pd != null) {
- loadMojoParameters(pd, mojo, parameters, monitor);
+ 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 null;
}
- }, monitor);
+ }
+ return parameters;
}
-
- return new MojoParameter("", mojo, plist); //$NON-NLS-1$
+ return loadMojoParameters(desc, desc.getMojo(goal), helper, monitor);
}
- private MojoParameter getPredefined() {
- return PREDEF.get(plugin.getGroupId() + ":" + plugin.getArtifactId() + ":" + plugin.getVersion());
+ private MojoParameter getPredefined(ArtifactKey pluginKey) {
+ return PREDEF.get(pluginKey.getGroupId() + ":" + pluginKey.getArtifactId() + ":" + pluginKey.getVersion());
}
- private void execute(final ICallable<Void> callable, IProgressMonitor monitor) throws CoreException {
+ <T> T execute(final ArtifactKey pluginKey, final ICallable<T> callable, IProgressMonitor monitor)
+ throws CoreException {
MavenExecutionContext context = maven.createExecutionContext();
context.getExecutionRequest().setCacheTransferError(false);
- context.execute(new ICallable<Void>() {
- public Void call(IMavenExecutionContext context, IProgressMonitor monitor) throws CoreException {
+ return 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);
@@ -207,84 +224,7 @@ public class MojoParameterMetadataProvider {
}, monitor);
}
- void loadMojoParameters(PluginDescriptor desc, String goal, List<MojoParameter> parameters, IProgressMonitor monitor)
- throws CoreException {
-
- Set<String> collected = new HashSet<>();
-
- if(goal.equals("*")) { //$NON-NLS-1$
- for(MojoDescriptor mojo : desc.getMojos()) {
- loadMojoParameters(desc, mojo, parameters, collected, monitor);
- }
- return;
- }
-
- MojoDescriptor mojo = desc.getMojo(goal);
- loadMojoParameters(desc, mojo, parameters, collected, monitor);
- }
-
- protected void loadMojoParameters(PluginDescriptor desc, MojoDescriptor mojo, List<MojoParameter> parameters,
- Set<String> collected, IProgressMonitor monitor) throws CoreException {
-
- if(monitor.isCanceled()) {
- return;
- }
- Class<?> clazz;
- try {
- clazz = mojo.getImplementationClass();
- if(clazz == null) {
- clazz = desc.getClassRealm().loadClass(mojo.getImplementation());
- }
- } catch(ClassNotFoundException | TypeNotPresentException ex) {
- log.warn(ex.getMessage());
- return;
- }
-
- List<Parameter> ps = mojo.getParameters();
- Map<String, Type> properties = getClassProperties(clazz);
-
- if(ps != null) {
- for(Parameter p : ps) {
- if(monitor.isCanceled()) {
- return;
- }
- if(!p.isEditable()) {
- continue;
- }
-
- Type type = properties.get(p.getName());
- if(type == null) {
- continue;
- }
-
- if(collected.add(p.getName())) {
- addParameter(desc, clazz, type, p.getName(), p.getAlias(), parameters, p.isRequired(), p.getExpression(),
- p.getDescription(), p.getDefaultValue(), monitor);
- }
- }
- }
- }
-
- protected void loadParameters(PluginDescriptor desc, Class<?> clazz, List<MojoParameter> parameters,
- IProgressMonitor monitor) throws CoreException {
- if(monitor.isCanceled()) {
- return;
- }
-
- Map<String, Type> properties = getClassProperties(clazz);
-
- for(Map.Entry<String, Type> e : properties.entrySet()) {
- if(monitor.isCanceled()) {
- return;
- }
- addParameter(desc, clazz, e.getValue(), e.getKey(), null, parameters, false, null, null, null, monitor);
- }
- }
-
- protected MavenProject getProject(IMavenExecutionContext context) {
- if(project != null) {
- return project;
- }
+ MavenProject getProject(IMavenExecutionContext context) {
ModelSource modelSource = new UrlModelSource(DefaultMaven.class.getResource("project/standalone.xml")); //$NON-NLS-1$
try {
@@ -295,9 +235,15 @@ public class MojoParameterMetadataProvider {
}
}
- PluginDescriptor getPluginDescriptor(IMavenExecutionContext context, IProgressMonitor monitor) {
+ 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());
@@ -314,403 +260,55 @@ public class MojoParameterMetadataProvider {
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));
+ throw new CoreException(
+ new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, -1, Messages.MavenImpl_error_lookup, ex));
}
}
- private void addParameter(PluginDescriptor desc, Class<?> enclosingClass, Type paramType, String name, String alias,
- List<MojoParameter> parameters, boolean required, String expression, String description, String defaultValue,
+ List<MojoParameter> loadMojoParameters(PluginDescriptor desc, MojoDescriptor mojo, PlexusConfigHelper helper,
IProgressMonitor monitor) throws CoreException {
- Class<?> paramClass = getRawType(paramType);
- if(paramClass == null) {
- return;
+ IMojoParameterMetadata metadata = null;
+ String mojoConfigurator = mojo.getComponentConfigurator();
+ if(mojoConfigurator != null) {
+ metadata = readMojoParameterMetadata(mojoConfigurator);
}
-
- // inline
- if(isInline(paramClass)) {
- parameters.add(configure(new MojoParameter(name, getTypeDisplayName(paramType)), required, expression,
- description, defaultValue));
- if(alias != null) {
- parameters.add(configure(new MojoParameter(alias, getTypeDisplayName(paramType)), required, expression,
- description, defaultValue));
- }
- return;
- }
-
- // map
- if(Map.class.isAssignableFrom(paramClass)) {
- // we can't do anything with maps, unfortunately
- parameters.add(configure(new MojoParameter(name, getTypeDisplayName(paramType)).map(), required, expression,
- description, defaultValue));
- if(alias != null) {
- parameters.add(configure(new MojoParameter(alias, getTypeDisplayName(paramType)).map(), required, expression,
- description, defaultValue));
- }
- return;
- }
-
- // properties
- if(Properties.class.isAssignableFrom(paramClass)) {
-
- MojoParameter inner = new MojoParameter("property", "property", Arrays.asList(
- new MojoParameter("name", "String"), new MojoParameter("value", "String")));
-
- parameters.add(configure(new MojoParameter(name, getTypeDisplayName(paramType), inner), required, expression,
- description, defaultValue));
- if(alias != null) {
- parameters.add(configure(new MojoParameter(alias, getTypeDisplayName(paramType), inner), required, expression,
- description, defaultValue));
- }
- }
-
- // collection/array
- Type itemType = getItemType(paramType);
-
- if(itemType != null) {
-
- List<MojoParameter> itemParameters = getItemParameters(desc, enclosingClass, name, itemType, monitor);
-
- parameters.add(configure(new MojoParameter(name, getTypeDisplayName(paramType), itemParameters), required,
- expression, description, defaultValue));
-
- if(alias != null) {
- itemParameters = getItemParameters(desc, enclosingClass, alias, itemType, monitor);
- parameters.add(configure(new MojoParameter(alias, getTypeDisplayName(paramType), itemParameters), required,
- expression, description, defaultValue));
- }
-
- return;
- }
-
- // pojo
- // skip classes without no-arg constructors
- try {
- paramClass.getConstructor(new Class[0]);
- } catch(NoSuchMethodException ex) {
- return;
- }
-
- List<MojoParameter> params = getParameters(desc, paramClass, monitor);
- parameters.add(configure(new MojoParameter(name, getTypeDisplayName(paramType), params), required, expression,
- description, defaultValue));
- if(alias != null) {
- parameters.add(configure(new MojoParameter(alias, getTypeDisplayName(paramType), params), required, expression,
- description, defaultValue));
+ if(metadata == null) {
+ metadata = new DefaultMojoParameterMetadata();
}
+ return metadata.loadMojoParameters(desc, mojo, helper, monitor);
}
- private List<MojoParameter> getItemParameters(PluginDescriptor desc, Class<?> enclosingClass, String name,
- Type paramType, IProgressMonitor monitor) throws CoreException {
-
- Class<?> paramClass = getRawType(paramType);
+ public static final String EXTENSION_MOJO_PARAMETER_METADATA = MvnIndexPlugin.PLUGIN_ID + ".mojoParameterMetadata"; //$NON-NLS-1$
- if(paramClass == null || isInline(paramClass)) {
- MojoParameter container = new MojoParameter(toSingular(name), getTypeDisplayName(paramType)).multiple();
- return Collections.singletonList(container);
- }
-
- if(Map.class.isAssignableFrom(paramClass) || Properties.class.isAssignableFrom(paramClass)) {
- MojoParameter container = new MojoParameter(toSingular(name), getTypeDisplayName(paramType)).multiple().map();
- return Collections.singletonList(container);
- }
-
- Type itemType = getItemType(paramType);
-
- if(itemType != null) {
- MojoParameter container = new MojoParameter(toSingular(name), getTypeDisplayName(paramType)).multiple();
- container.setNestedParameters(getItemParameters(desc, enclosingClass, name, itemType, monitor));
- return Collections.singletonList(container);
- }
+ private static IMojoParameterMetadata readMojoParameterMetadata(String mojoConfigurator) {
- @SuppressWarnings("rawtypes")
- List<Class> parameterClasses = getCandidateClasses(desc, enclosingClass, paramClass);
-
- List<MojoParameter> parameters = new ArrayList<>();
- for(Class<?> clazz : parameterClasses) {
-
- String paramName;
- if(clazz.equals(paramClass)) {
- paramName = toSingular(name);
- } else {
- paramName = clazz.getSimpleName();
- paramName = Character.toLowerCase(paramName.charAt(0)) + paramName.substring(1);
- }
-
- MojoParameter container = new MojoParameter(paramName, getTypeDisplayName(clazz)).multiple();
- container.setNestedParameters(getParameters(desc, clazz, monitor));
- parameters.add(container);
- }
-
- return parameters;
- }
-
- private static MojoParameter configure(MojoParameter p, boolean required, String expression, String description,
- String defaultValue) {
- p.setRequired(required);
- p.setExpression(expression);
- p.setDescription(description);
- p.setDefaultValue(defaultValue);
- return p;
- }
-
- private static Class<?> getRawType(Type type) {
- if(type instanceof Class) {
- return (Class<?>) type;
- }
- if(type instanceof ParameterizedType) {
- return (Class<?>) ((ParameterizedType) type).getRawType();
- }
- return null;
- }
-
- private static Type getItemType(Type paramType) {
-
- Class<?> paramClass = getRawType(paramType);
-
- if(paramClass != null && paramClass.isArray()) {
- return paramClass.getComponentType();
- }
- if(!Collection.class.isAssignableFrom(paramClass)) {
- return null;
- }
-
- if(paramType instanceof ParameterizedType) {
- ParameterizedType pt = (ParameterizedType) paramType;
-
- Type[] args = pt.getActualTypeArguments();
- if(args.length > 0) {
- return args[0];
- }
- }
-
- return null;
- }
-
- private static Map<String, Type> getClassProperties(Class<?> clazz) {
- Map<String, Type> props = new HashMap<>();
-
- Method[] methods;
- try {
- methods = clazz.getMethods();
- } catch(Throwable e) {
- log.debug("Cannot get methods of " + clazz.getName(), e);
- methods = null;
- }
-
- if(methods != null) {
- for(Method m : methods) {
- if((m.getModifiers() & Modifier.STATIC) != 0) {
- continue;
- }
-
- String name = m.getName();
-
- if((name.startsWith("add") || name.startsWith("set")) && m.getParameterTypes().length == 1) { //$NON-NLS-1$ //$NON-NLS-2$
- String prop = name.substring(3);
- if(!prop.isEmpty()) {
- prop = Character.toLowerCase(prop.charAt(0)) + prop.substring(1);
- if(!props.containsKey(prop)) {
- props.put(prop, m.getGenericParameterTypes()[0]);
+ 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);
}
}
}
}
}
-
- Class<?> pClazz = clazz;
- while(pClazz != null && !pClazz.equals(Object.class)) {
-
- Field[] fields;
- try {
- fields = pClazz.getDeclaredFields();
- } catch(Throwable e) {
- log.debug("Cannot get declared fields of " + pClazz.getName(), e);
- fields = null;
- }
-
- if(fields != null) {
- for(Field f : fields) {
- if((f.getModifiers() & (Modifier.STATIC | Modifier.FINAL)) != 0) {
- continue;
- }
-
- String prop = f.getName();
-
- if(!props.containsKey(prop)) {
-
- props.put(prop, f.getGenericType());
-
- }
- }
- }
- pClazz = pClazz.getSuperclass();
-
- }
-
- return props;
- }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- private static List<Class> getCandidateClasses(PluginDescriptor desc, Class enclosingClass, Class paramClass) {
-
- String name = enclosingClass.getName();
- int dot = name.lastIndexOf('.');
- if(dot > 0) {
- String pkg = name.substring(0, dot);
-
- List<Class> candidateClasses = null;
-
- ClassPath cp;
- try {
- cp = ClassPath.from(desc.getClassRealm());
- } catch(IOException e) {
- log.error(e.getMessage());
- return Collections.singletonList(enclosingClass);
- }
-
- for(ClassInfo ci : cp.getTopLevelClasses(pkg)) {
- Class clazz;
- try {
- clazz = desc.getClassRealm().loadClass(ci.getName());
- } catch(ClassNotFoundException e) {
- log.error(e.getMessage(), e);
- continue;
- }
-
- if((clazz.getModifiers() & (Modifier.ABSTRACT)) != 0) {
- continue;
- }
-
- if(!paramClass.isAssignableFrom(clazz)) {
- continue;
- }
-
- // skip classes without no-arg constructors
- try {
- clazz.getConstructor(new Class[0]);
- } catch(NoSuchMethodException ex) {
- continue;
- }
-
- if(candidateClasses == null) {
- candidateClasses = new ArrayList<Class>();
- }
- candidateClasses.add(clazz);
-
- }
-
- if(candidateClasses != null) {
- return candidateClasses;
- }
- }
-
- return Collections.singletonList(paramClass);
- }
-
- private static boolean isInline(Class<?> paramClass) {
- return INLINE_TYPES.contains(paramClass.getName()) || paramClass.isEnum();
- }
-
- private static String getTypeDisplayName(Type type) {
- Class<?> clazz = getRawType(type);
-
- if(clazz == null) {
- return type.toString();
- }
-
- if(clazz.isArray()) {
- return getTypeDisplayName(clazz.getComponentType()) + "[]"; //$NON-NLS-1$
- }
-
- if(type instanceof ParameterizedType) {
- ParameterizedType ptype = (ParameterizedType) type;
- StringBuilder sb = new StringBuilder();
- sb.append(getTypeDisplayName(clazz)).append("&lt;"); //$NON-NLS-1$
-
- boolean first = true;
- for(Type arg : ptype.getActualTypeArguments()) {
- if(first)
- first = false;
- else
- sb.append(", "); //$NON-NLS-1$
- sb.append(getTypeDisplayName(arg));
- }
-
- return sb.append("&gt;").toString(); //$NON-NLS-1$
- }
-
- String name = clazz.getName();
- int idx = name.lastIndexOf('.');
- if(idx == -1) {
- return name;
- }
- // remove common package names
- String pkg = name.substring(0, idx);
- if(pkg.equals("java.lang") || pkg.equals("java.util") || pkg.equals("java.io")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- return clazz.getSimpleName();
- }
- return name;
- }
-
- private static String toSingular(String name) {
- if(name == null || name.trim().isEmpty()) {
- return name;
- }
- if(name.endsWith("ies")) { //$NON-NLS-1$
- return name.substring(0, name.length() - 3) + "y"; //$NON-NLS-1$
- } else if(name.endsWith("ches")) { //$NON-NLS-1$ $NON-NLS-2$
- return name.substring(0, name.length() - 2);
- } else if(name.endsWith("xes")) { //$NON-NLS-1$
- return name.substring(0, name.length() - 2);
- } else if(name.endsWith("s") && (name.length() != 1)) { //$NON-NLS-1$
- return name.substring(0, name.length() - 1);
- }
- return name;
+ return null;
}
- private static final Set<String> INLINE_TYPES;
-
private static final Map<String, MojoParameter> PREDEF;
static {
// @formatter:off
- INLINE_TYPES = ImmutableSet.<String>of(
- byte.class.getName(),
- Byte.class.getName(),
- short.class.getName(),
- Short.class.getName(),
- int.class.getName(),
- Integer.class.getName(),
- long.class.getName(),
- Long.class.getName(),
- float.class.getName(),
- Float.class.getName(),
- double.class.getName(),
- Double.class.getName(),
- boolean.class.getName(),
- Boolean.class.getName(),
- char.class.getName(),
- Character.class.getName(),
-
- String.class.getName(),
- StringBuilder.class.getName(),
- StringBuffer.class.getName(),
-
- File.class.getName(),
- URI.class.getName(),
- URL.class.getName(),
- Date.class.getName(),
-
- "org.codehaus.plexus.configuration.PlexusConfiguration"
- );
- // @formatter:on
- }
-
- static {
- // @formatter:off
PREDEF = ImmutableMap.<String, MojoParameter>of(
"org.eclipse.m2e:lifecycle-mapping:1.0.0",
new MojoParameter("", "", Collections.singletonList(
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/IMojoParameterMetadata.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/IMojoParameterMetadata.java
new file mode 100644
index 00000000..7e8b7c3b
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/IMojoParameterMetadata.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * 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.mojo;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+
+
+/**
+ * @since 1.6
+ */
+public interface IMojoParameterMetadata {
+
+ /**
+ * Returns a list of parameters that are applicable to a specified plugin mojo
+ */
+ List<MojoParameter> loadMojoParameters(PluginDescriptor desc, MojoDescriptor mojo, PlexusConfigHelper helper,
+ IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/IMojoParameterMetadataProvider.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/IMojoParameterMetadataProvider.java
new file mode 100644
index 00000000..5ee6f609
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/IMojoParameterMetadataProvider.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * 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.mojo;
+
+import java.util.Collection;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+
+
+/**
+ * Provides available configuration options for maven plugin executions
+ *
+ * @author atanasenko
+ * @since 1.6
+ */
+public interface IMojoParameterMetadataProvider {
+
+ /**
+ * Calculates available configuration of one specific mojo.
+ */
+ public MojoParameter getMojoConfiguration(ArtifactKey pluginKey, String mojo, IProgressMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Calculates available configuration of a number of mojos.
+ */
+ public MojoParameter getMojoConfiguration(ArtifactKey pluginKey, Collection<String> mojos, IProgressMonitor monitor)
+ throws CoreException;
+
+ /**
+ * Calculates available configuration of all mojos provided by specified plugin.
+ */
+ public MojoParameter getMojoConfiguration(ArtifactKey pluginKey, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Calculates available configuration of a single plugin class.
+ */
+ public MojoParameter getClassConfiguration(ArtifactKey pluginKey, String className, IProgressMonitor monitor)
+ throws CoreException;
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/mojo/MojoParameter.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/MojoParameter.java
index 57814148..2b2702e9 100644
--- a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/mojo/MojoParameter.java
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/MojoParameter.java
@@ -9,14 +9,14 @@
* Anton Tanasenko. - initial API and implementation
*******************************************************************************/
-package org.eclipse.m2e.editor.xml.internal.mojo;
+package org.eclipse.m2e.editor.xml.mojo;
import java.util.Collections;
import java.util.List;
/**
- * @author atanasenko
+ * @since 1.6
*/
public class MojoParameter {
@@ -48,16 +48,16 @@ public class MojoParameter {
this(name, type, Collections.singletonList(parameter));
}
- protected MojoParameter(String name, String type) {
+ public MojoParameter(String name, String type) {
this(name, type, Collections.<MojoParameter> emptyList());
}
- MojoParameter multiple() {
+ public MojoParameter multiple() {
this.multiple = true;
return this;
}
- MojoParameter map() {
+ public MojoParameter map() {
this.map = true;
return this;
}
@@ -71,11 +71,7 @@ public class MojoParameter {
}
public List<MojoParameter> getNestedParameters() {
- return Collections.unmodifiableList(nested);
- }
-
- void setNestedParameters(List<MojoParameter> nested) {
- this.nested = nested;
+ return nested == null ? Collections.<MojoParameter> emptyList() : Collections.unmodifiableList(nested);
}
public String getName() {
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/PlexusConfigHelper.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/PlexusConfigHelper.java
new file mode 100644
index 00000000..b5287132
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/mojo/PlexusConfigHelper.java
@@ -0,0 +1,460 @@
+/*******************************************************************************
+ * 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.mojo;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.ClassPath;
+import com.google.common.reflect.ClassPath.ClassInfo;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+
+
+/**
+ * Mirrors logic implemented in default maven mojo configurator with regards to discovering how a PlexusConfiguration
+ * can be applied to an arbitrary object tree.
+ *
+ * @see org.codehaus.plexus.component.configurator.BasicComponentConfigurator
+ * @see org.codehaus.plexus.component.configurator.converters.lookup.DefaultConverterLookup
+ * @see org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter
+ * @since 1.6
+ */
+public class PlexusConfigHelper {
+
+ private static final Logger log = LoggerFactory.getLogger(PlexusConfigHelper.class);
+
+ private Map<Class<?>, List<MojoParameter>> processedClasses;
+
+ public PlexusConfigHelper() {
+ processedClasses = new HashMap<>();
+ }
+
+ public List<MojoParameter> loadParameters(ClassRealm realm, Class<?> paramClass, IProgressMonitor monitor)
+ throws CoreException {
+
+ if(monitor.isCanceled()) {
+ return Collections.emptyList();
+ }
+
+ List<MojoParameter> parameters = processedClasses.get(paramClass);
+ if(parameters == null) {
+ parameters = new ArrayList<>();
+ processedClasses.put(paramClass, parameters);
+
+ log.debug("Loading properties of {}", paramClass.getName());
+ Map<String, Type> properties = getClassProperties(paramClass);
+
+ for(Map.Entry<String, Type> e : properties.entrySet()) {
+ if(!monitor.isCanceled()) {
+ addParameter(realm, paramClass, e.getValue(), e.getKey(), null, parameters, false, null, null, null, monitor);
+ }
+ }
+ }
+
+ return parameters;
+ }
+
+ public void addParameter(ClassRealm realm, Class<?> enclosingClass, Type paramType, String name, String alias,
+ List<MojoParameter> parameters, boolean required, String expression, String description, String defaultValue,
+ IProgressMonitor monitor) throws CoreException {
+
+ Class<?> paramClass = getRawType(paramType);
+ if(paramClass == null) {
+ return;
+ }
+
+ // inline
+ if(isInline(paramClass)) {
+ parameters.add(configure(new MojoParameter(name, getTypeDisplayName(paramType)), required, expression,
+ description, defaultValue));
+ if(alias != null) {
+ parameters.add(configure(new MojoParameter(alias, getTypeDisplayName(paramType)), required, expression,
+ description, defaultValue));
+ }
+ return;
+ }
+
+ // map
+ if(Map.class.isAssignableFrom(paramClass)) {
+ // we can't do anything with maps, unfortunately
+ parameters.add(configure(new MojoParameter(name, getTypeDisplayName(paramType)).map(), required, expression,
+ description, defaultValue));
+ if(alias != null) {
+ parameters.add(configure(new MojoParameter(alias, getTypeDisplayName(paramType)).map(), required, expression,
+ description, defaultValue));
+ }
+ return;
+ }
+
+ // properties
+ if(Properties.class.isAssignableFrom(paramClass)) {
+
+ MojoParameter nested = new MojoParameter("property", "property",
+ Arrays.asList(new MojoParameter("name", "String"), new MojoParameter("value", "String")));
+
+ parameters.add(configure(new MojoParameter(name, getTypeDisplayName(paramType), nested), required, expression,
+ description, defaultValue));
+ if(alias != null) {
+ parameters.add(configure(new MojoParameter(alias, getTypeDisplayName(paramType), nested), required, expression,
+ description, defaultValue));
+ }
+ }
+
+ // collection/array
+ Type itemType = getItemType(paramType);
+
+ if(itemType != null) {
+
+ List<MojoParameter> nested = getItemParameters(realm, enclosingClass, name, itemType, monitor);
+
+ parameters.add(configure(new MojoParameter(name, getTypeDisplayName(paramType), nested), required, expression,
+ description, defaultValue));
+
+ if(alias != null) {
+ nested = getItemParameters(realm, enclosingClass, alias, itemType, monitor);
+ parameters.add(configure(new MojoParameter(alias, getTypeDisplayName(paramType), nested), required, expression,
+ description, defaultValue));
+ }
+
+ return;
+ }
+
+ // pojo
+ // skip classes without no-arg constructors
+ try {
+ paramClass.getConstructor(new Class[0]);
+ } catch(NoSuchMethodException ex) {
+ return;
+ }
+
+ List<MojoParameter> nested = loadParameters(realm, paramClass, monitor);
+ parameters.add(configure(new MojoParameter(name, getTypeDisplayName(paramType), nested), required, expression,
+ description, defaultValue));
+ if(alias != null) {
+ parameters.add(configure(new MojoParameter(alias, getTypeDisplayName(paramType), nested), required, expression,
+ description, defaultValue));
+ }
+
+ }
+
+ public List<MojoParameter> getItemParameters(ClassRealm realm, Class<?> enclosingClass, String name, Type paramType,
+ IProgressMonitor monitor) throws CoreException {
+
+ Class<?> paramClass = getRawType(paramType);
+
+ if(paramClass == null || isInline(paramClass)) {
+ MojoParameter container = new MojoParameter(toSingularName(name), getTypeDisplayName(paramType)).multiple();
+ return Collections.singletonList(container);
+ }
+
+ if(Map.class.isAssignableFrom(paramClass) || Properties.class.isAssignableFrom(paramClass)) {
+ MojoParameter container = new MojoParameter(toSingularName(name), getTypeDisplayName(paramType)).multiple().map();
+ return Collections.singletonList(container);
+ }
+
+ Type itemType = getItemType(paramType);
+
+ if(itemType != null) {
+ List<MojoParameter> nested = getItemParameters(realm, enclosingClass, name, itemType, monitor);
+ MojoParameter container = new MojoParameter(toSingularName(name), getTypeDisplayName(paramType), nested)
+ .multiple();
+ return Collections.singletonList(container);
+ }
+
+ @SuppressWarnings("rawtypes")
+ List<Class> parameterClasses = getCandidateClasses(realm, enclosingClass, paramClass);
+
+ List<MojoParameter> parameters = new ArrayList<>();
+ for(Class<?> clazz : parameterClasses) {
+
+ String paramName;
+ if(clazz.equals(paramClass)) {
+ paramName = toSingularName(name);
+ } else {
+ paramName = clazz.getSimpleName();
+ paramName = Character.toLowerCase(paramName.charAt(0)) + paramName.substring(1);
+ }
+
+ List<MojoParameter> nested = loadParameters(realm, paramClass, monitor);
+ MojoParameter container = new MojoParameter(paramName, getTypeDisplayName(clazz), nested).multiple();
+ parameters.add(container);
+ }
+
+ return parameters;
+ }
+
+ public static MojoParameter configure(MojoParameter p, boolean required, String expression, String description,
+ String defaultValue) {
+ p.setRequired(required);
+ p.setExpression(expression);
+ p.setDescription(description);
+ p.setDefaultValue(defaultValue);
+ return p;
+ }
+
+ public static Class<?> getRawType(Type type) {
+ if(type instanceof Class) {
+ return (Class<?>) type;
+ }
+ if(type instanceof ParameterizedType) {
+ return (Class<?>) ((ParameterizedType) type).getRawType();
+ }
+ return null;
+ }
+
+ public static Type getItemType(Type paramType) {
+
+ Class<?> paramClass = getRawType(paramType);
+
+ if(paramClass != null && paramClass.isArray()) {
+ return paramClass.getComponentType();
+ }
+ if(!Collection.class.isAssignableFrom(paramClass)) {
+ return null;
+ }
+
+ if(paramType instanceof ParameterizedType) {
+ ParameterizedType pt = (ParameterizedType) paramType;
+
+ Type[] args = pt.getActualTypeArguments();
+ if(args.length > 0) {
+ return args[0];
+ }
+ }
+
+ return null;
+ }
+
+ public Map<String, Type> getClassProperties(Class<?> clazz) {
+ Map<String, Type> props = new HashMap<>();
+
+ for(Method m : clazz.getMethods()) {
+ if((m.getModifiers() & Modifier.STATIC) != 0) {
+ continue;
+ }
+
+ String name = m.getName();
+
+ if((name.startsWith("add") || name.startsWith("set")) && m.getParameterTypes().length == 1) { //$NON-NLS-1$ //$NON-NLS-2$
+ String prop = name.substring(3);
+ if(!prop.isEmpty()) {
+ prop = Character.toLowerCase(prop.charAt(0)) + prop.substring(1);
+ if(!props.containsKey(prop)) {
+ props.put(prop, m.getGenericParameterTypes()[0]);
+ }
+ }
+ }
+ }
+
+ Class<?> pClazz = clazz;
+ while(pClazz != null && !pClazz.equals(Object.class)) {
+
+ for(Field f : pClazz.getDeclaredFields()) {
+ if((f.getModifiers() & (Modifier.STATIC | Modifier.FINAL)) != 0) {
+ continue;
+ }
+
+ String prop = f.getName();
+
+ if(!props.containsKey(prop)) {
+
+ props.put(prop, f.getGenericType());
+
+ }
+ }
+ pClazz = pClazz.getSuperclass();
+
+ }
+
+ return props;
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public List<Class> getCandidateClasses(ClassRealm realm, Class enclosingClass, Class paramClass) {
+
+ String name = enclosingClass.getName();
+ int dot = name.lastIndexOf('.');
+ if(dot > 0) {
+ String pkg = name.substring(0, dot);
+
+ List<Class> candidateClasses = null;
+
+ ClassPath cp;
+ try {
+ cp = ClassPath.from(realm);
+ } catch(IOException e) {
+ log.error(e.getMessage());
+ return Collections.singletonList(enclosingClass);
+ }
+
+ for(ClassInfo ci : cp.getTopLevelClasses(pkg)) {
+ Class clazz;
+ try {
+ clazz = realm.loadClass(ci.getName());
+ } catch(ClassNotFoundException e) {
+ log.error(e.getMessage(), e);
+ continue;
+ }
+
+ if((clazz.getModifiers() & (Modifier.ABSTRACT)) != 0) {
+ continue;
+ }
+
+ if(!paramClass.isAssignableFrom(clazz)) {
+ continue;
+ }
+
+ // skip classes without no-arg constructors
+ try {
+ clazz.getConstructor(new Class[0]);
+ } catch(NoSuchMethodException ex) {
+ continue;
+ }
+
+ if(candidateClasses == null) {
+ candidateClasses = new ArrayList<Class>();
+ }
+ candidateClasses.add(clazz);
+
+ }
+
+ if(candidateClasses != null) {
+ return candidateClasses;
+ }
+ }
+
+ return Collections.singletonList(paramClass);
+ }
+
+ public static boolean isInline(Class<?> paramClass) {
+ return INLINE_TYPES.contains(paramClass.getName()) || paramClass.isEnum();
+ }
+
+ public static String getTypeDisplayName(Type type) {
+ Class<?> clazz = getRawType(type);
+
+ if(clazz == null) {
+ return type.toString();
+ }
+
+ if(clazz.isArray()) {
+ return getTypeDisplayName(clazz.getComponentType()) + "[]"; //$NON-NLS-1$
+ }
+
+ if(type instanceof ParameterizedType) {
+ ParameterizedType ptype = (ParameterizedType) type;
+ StringBuilder sb = new StringBuilder();
+ sb.append(getTypeDisplayName(clazz)).append("&lt;"); //$NON-NLS-1$
+
+ boolean first = true;
+ for(Type arg : ptype.getActualTypeArguments()) {
+ if(first)
+ first = false;
+ else
+ sb.append(", "); //$NON-NLS-1$
+ sb.append(getTypeDisplayName(arg));
+ }
+
+ return sb.append("&gt;").toString(); //$NON-NLS-1$
+ }
+
+ String name = clazz.getName();
+ int idx = name.lastIndexOf('.');
+ if(idx == -1) {
+ return name;
+ }
+ // remove common package names
+ String pkg = name.substring(0, idx);
+ if(pkg.equals("java.lang") || pkg.equals("java.util") || pkg.equals("java.io")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ return clazz.getSimpleName();
+ }
+ return name;
+ }
+
+ public String toSingularName(String name) {
+ if(name == null || name.trim().isEmpty()) {
+ return name;
+ }
+ if(name.endsWith("ies")) { //$NON-NLS-1$
+ return name.substring(0, name.length() - 3) + "y"; //$NON-NLS-1$
+ } else if(name.endsWith("ches")) { //$NON-NLS-1$ $NON-NLS-2$
+ return name.substring(0, name.length() - 2);
+ } else if(name.endsWith("xes")) { //$NON-NLS-1$
+ return name.substring(0, name.length() - 2);
+ } else if(name.endsWith("s") && (name.length() != 1)) { //$NON-NLS-1$
+ return name.substring(0, name.length() - 1);
+ }
+ return name;
+ }
+
+ private static final Set<String> INLINE_TYPES;
+
+ static {
+ // @formatter:off
+ INLINE_TYPES = ImmutableSet.<String>of(
+ byte.class.getName(),
+ Byte.class.getName(),
+ short.class.getName(),
+ Short.class.getName(),
+ int.class.getName(),
+ Integer.class.getName(),
+ long.class.getName(),
+ Long.class.getName(),
+ float.class.getName(),
+ Float.class.getName(),
+ double.class.getName(),
+ Double.class.getName(),
+ boolean.class.getName(),
+ Boolean.class.getName(),
+ char.class.getName(),
+ Character.class.getName(),
+
+ String.class.getName(),
+ StringBuilder.class.getName(),
+ StringBuffer.class.getName(),
+
+ File.class.getName(),
+ URI.class.getName(),
+ URL.class.getName(),
+ Date.class.getName(),
+
+ "org.codehaus.plexus.configuration.PlexusConfiguration"
+ );
+ // @formatter:on
+ }
+
+}

Back to the top