blob: ba5a944b360c570a72db291e01854e7ccc5f22e9 [file] [log] [blame]
package org.jetbrains.idea.maven.plugins.api;
import com.intellij.lang.Language;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.PsiReferenceProvider;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlText;
import com.intellij.psi.xml.XmlTokenType;
import com.intellij.util.ProcessingContext;
import com.intellij.util.SmartList;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.DomManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.dom.model.*;
import org.jetbrains.idea.maven.utils.MavenUtil;
import java.util.*;
/**
* @author Sergey Evdokimov
*/
public class MavenPluginParamInfo {
private static final Logger LOG = Logger.getInstance(MavenPluginParamInfo.class);
/**
* This map contains descriptions of all plugins.
*/
private static volatile Map<String, Map> myMap;
public static Map<String, Map> getMap() {
Map<String, Map> res = myMap;
if (res == null) {
res = new HashMap<String, Map>();
for (MavenPluginDescriptor pluginDescriptor : MavenPluginDescriptor.EP_NAME.getExtensions()) {
if (pluginDescriptor.params == null) continue;
Pair<String, String> pluginId = MavenPluginDescriptor.parsePluginId(pluginDescriptor.mavenId);
for (MavenPluginDescriptor.Param param : pluginDescriptor.params) {
String[] paramPath = param.name.split("/");
Map pluginsMap = res;
for (int i = paramPath.length - 1; i >= 0; i--) {
pluginsMap = MavenUtil.getOrCreate(pluginsMap, paramPath[i]);
}
ParamInfo paramInfo = new ParamInfo(pluginDescriptor.getPluginDescriptor().getPluginClassLoader(), param);
Map<String, ParamInfo> goalsMap = MavenUtil.getOrCreate(pluginsMap, pluginId);
String goal = pluginDescriptor.goal;
assert goal == null || !goal.isEmpty();
ParamInfo oldValue = goalsMap.put(goal, paramInfo);
if (oldValue != null) {
LOG.error("Duplicated maven plugin parameter descriptor: "
+ pluginId.first + ':' + pluginId.second + " -> "
+ (goal != null ? "[" + goal + ']' : "") + param.name);
}
}
}
myMap = res;
}
return res;
}
public static boolean isSimpleText(@NotNull XmlText paramValue) {
PsiElement prevSibling = paramValue.getPrevSibling();
if (!(prevSibling instanceof LeafPsiElement) || ((LeafPsiElement)prevSibling).getElementType() != XmlTokenType.XML_TAG_END) {
return false;
}
PsiElement nextSibling = paramValue.getNextSibling();
if (!(nextSibling instanceof LeafPsiElement) || ((LeafPsiElement)nextSibling).getElementType() != XmlTokenType.XML_END_TAG_START) {
return false;
}
return true;
}
public static ParamInfoList getParamInfoList(@NotNull XmlText paramValue) {
XmlTag tag = paramValue.getParentTag();
if (tag == null) return ParamInfoList.EMPTY;
return getParamInfoList(tag);
}
public static ParamInfoList getParamInfoList(@NotNull XmlTag paramTag) {
XmlTag configurationTag = paramTag;
DomElement domElement;
Map m = getMap().get(paramTag.getName());
while (true) {
if (m == null) return ParamInfoList.EMPTY;
configurationTag = configurationTag.getParentTag();
if (configurationTag == null) return ParamInfoList.EMPTY;
String tagName = configurationTag.getName();
if ("configuration".equals(tagName)) {
domElement = DomManager.getDomManager(configurationTag.getProject()).getDomElement(configurationTag);
if (domElement instanceof MavenDomConfiguration) {
break;
}
if (domElement != null) return ParamInfoList.EMPTY;
}
m = (Map)m.get(tagName);
}
Map<Pair<String, String>, Map<String, ParamInfo>> pluginsMap = m;
MavenDomConfiguration domCfg = (MavenDomConfiguration)domElement;
MavenDomPlugin domPlugin = domCfg.getParentOfType(MavenDomPlugin.class, true);
if (domPlugin == null) return ParamInfoList.EMPTY;
String pluginGroupId = domPlugin.getGroupId().getStringValue();
String pluginArtifactId = domPlugin.getArtifactId().getStringValue();
Map<String, ParamInfo> goalsMap;
if (pluginGroupId == null) {
goalsMap = pluginsMap.get(Pair.create("org.apache.maven.plugins", pluginArtifactId));
if (goalsMap == null) {
goalsMap = pluginsMap.get(Pair.create("org.codehaus.mojo", pluginArtifactId));
}
}
else {
goalsMap = pluginsMap.get(Pair.create(pluginGroupId, pluginArtifactId));
}
if (goalsMap == null) return ParamInfoList.EMPTY;
DomElement parent = domCfg.getParent();
if (parent instanceof MavenDomPluginExecution) {
SmartList<ParamInfo> infos = null;
MavenDomGoals goals = ((MavenDomPluginExecution)parent).getGoals();
for (MavenDomGoal goal : goals.getGoals()) {
ParamInfo info = goalsMap.get(goal.getStringValue());
if (info != null) {
if (infos == null) {
infos = new SmartList<ParamInfo>();
}
infos.add(info);
}
}
if (infos != null) {
ParamInfo defaultInfo = goalsMap.get(null);
if (defaultInfo != null) {
infos.add(defaultInfo);
}
return new ParamInfoList(domCfg, infos);
}
}
ParamInfo defaultInfo = goalsMap.get(null);
if (defaultInfo != null) {
return new ParamInfoList(domCfg, Collections.singletonList(defaultInfo));
}
return ParamInfoList.EMPTY;
}
public static class ParamInfoList implements Iterable<ParamInfo> {
private static final ParamInfoList EMPTY = new ParamInfoList(null, Collections.<ParamInfo>emptyList());
private final MavenDomConfiguration domCfg;
private final List<ParamInfo> paramInfos;
ParamInfoList(MavenDomConfiguration domCfg, @NotNull List<ParamInfo> paramInfos) {
this.domCfg = domCfg;
this.paramInfos = paramInfos;
}
public MavenDomConfiguration getDomCfg() {
return domCfg;
}
@Override
public Iterator<ParamInfo> iterator() {
return paramInfos.iterator();
}
}
public static class ParamInfo {
private final ClassLoader myClassLoader;
private final MavenPluginDescriptor.Param myParam;
private volatile boolean myLanguageInitialized;
private Language myLanguageInstance;
private MavenParamLanguageProvider myLanguageProvider;
private volatile boolean myProviderInitialized;
private volatile MavenParamReferenceProvider myProviderInstance;
private ParamInfo(ClassLoader classLoader, MavenPluginDescriptor.Param param) {
myClassLoader = classLoader;
myParam = param;
}
private void ensureLanguageInit() {
if (!myLanguageInitialized) {
if (myParam.language != null) {
assert myParam.languageProvider == null;
myLanguageInstance = Language.findLanguageByID(myParam.language);
}
else if (myParam.languageProvider != null) {
try {
myLanguageProvider = (MavenParamLanguageProvider)myClassLoader.loadClass(myParam.languageProvider).newInstance();
}
catch (Exception e) {
throw new RuntimeException("Failed to create language provider instance", e);
}
}
myLanguageInitialized = true;
}
}
@Nullable
public Language getLanguage() {
ensureLanguageInit();
return myLanguageInstance;
}
@Nullable
public MavenParamLanguageProvider getLanguageProvider() {
ensureLanguageInit();
return myLanguageProvider;
}
public MavenPluginDescriptor.Param getParam() {
return myParam;
}
public String getLanguageInjectionPrefix() {
return myParam.languageInjectionPrefix;
}
public String getLanguageInjectionSuffix() {
return myParam.languageInjectionSuffix;
}
public MavenParamReferenceProvider getProviderInstance() {
if (!myProviderInitialized) {
MavenParamReferenceProvider res = null;
if (myParam.refProvider != null) {
assert myParam.values == null : myParam.name;
Object instance;
try {
instance = myClassLoader.loadClass(myParam.refProvider).newInstance();
}
catch (Exception e) {
throw new RuntimeException("Failed to create reference provider instance", e);
}
if (instance instanceof MavenParamReferenceProvider) {
res = (MavenParamReferenceProvider)instance;
}
else {
res = new PsiReferenceProviderWrapper((PsiReferenceProvider)instance);
}
}
else if (myParam.values != null) {
StringTokenizer st = new StringTokenizer(myParam.values, " ,;");
int n = st.countTokens();
if (n == 0) throw new RuntimeException("Incorrect value of 'values' attribute for param " + myParam.name);
String[] values = new String[n];
for (int i = 0; i < n; i++) {
values[i] = st.nextToken();
}
res = new MavenFixedValueReferenceProvider(values);
}
if (res != null && myParam.soft != null) {
((MavenSoftAwareReferenceProvider)res).setSoft(myParam.soft);
}
myProviderInstance = res;
myProviderInitialized = true;
}
return myProviderInstance;
}
}
private static class PsiReferenceProviderWrapper implements MavenParamReferenceProvider, MavenSoftAwareReferenceProvider {
private final PsiReferenceProvider myProvider;
private PsiReferenceProviderWrapper(PsiReferenceProvider provider) {
this.myProvider = provider;
}
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement element,
@NotNull MavenDomConfiguration domCfg,
@NotNull ProcessingContext context) {
return myProvider.getReferencesByElement(element, context);
}
@Override
public void setSoft(boolean soft) {
((MavenSoftAwareReferenceProvider)myProvider).setSoft(soft);
}
}
}