2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org
.jetbrains
.idea
.devkit
.dom
.impl
;
18 import com
.intellij
.ide
.plugins
.PluginManager
;
19 import com
.intellij
.openapi
.util
.text
.StringUtil
;
20 import com
.intellij
.openapi
.vfs
.VirtualFile
;
21 import com
.intellij
.psi
.*;
22 import com
.intellij
.psi
.search
.GlobalSearchScope
;
23 import com
.intellij
.psi
.xml
.XmlElement
;
24 import com
.intellij
.psi
.xml
.XmlFile
;
25 import com
.intellij
.util
.containers
.ContainerUtil
;
26 import com
.intellij
.util
.xml
.*;
27 import com
.intellij
.util
.xml
.reflect
.DomExtender
;
28 import com
.intellij
.util
.xml
.reflect
.DomExtension
;
29 import com
.intellij
.util
.xml
.reflect
.DomExtensionsRegistrar
;
30 import com
.intellij
.util
.xmlb
.annotations
.Attribute
;
31 import com
.intellij
.util
.xmlb
.annotations
.Tag
;
32 import org
.jetbrains
.annotations
.NotNull
;
33 import org
.jetbrains
.annotations
.Nullable
;
34 import org
.jetbrains
.idea
.devkit
.dom
.*;
36 import java
.util
.Collection
;
37 import java
.util
.HashSet
;
43 public class ExtensionDomExtender
extends DomExtender
<Extensions
> {
44 private static final PsiClassConverter CLASS_CONVERTER
= new PluginPsiClassConverter();
47 public void registerExtensions(@NotNull final Extensions extensions
, @NotNull final DomExtensionsRegistrar registrar
) {
48 final XmlElement xmlElement
= extensions
.getXmlElement();
49 if (xmlElement
== null) return;
50 final PsiManager psiManager
= xmlElement
.getManager();
52 IdeaPlugin ideaPlugin
= extensions
.getParentOfType(IdeaPlugin
.class, true);
54 if (ideaPlugin
== null) return;
56 String prefix
= extensions
.getDefaultExtensionNs().getStringValue();
57 if (prefix
== null) prefix
= extensions
.getXmlns().getStringValue();
64 final Collection
<String
> dependencies
= getDependencies(ideaPlugin
);
65 ContainerUtil
.addIfNotNull(ideaPlugin
.getPluginId(), dependencies
);
66 for (IdeaPlugin plugin
: IdeaPluginConverter
.collectAllVisiblePlugins(DomUtil
.getFile(extensions
))) {
67 final String value
= plugin
.getPluginId();
68 if (value
!= null && dependencies
.contains(value
)) {
69 registerExtensions(prefix
, plugin
, registrar
, psiManager
);
75 private static void registerExtensions(final String prefix
, final IdeaPlugin plugin
, final DomExtensionsRegistrar registrar
,
76 final PsiManager psiManager
) {
77 final String pluginId
= plugin
.getPluginId();
78 for (ExtensionPoints points
: plugin
.getExtensionPoints()) {
79 for (ExtensionPoint point
: points
.getExtensionPoints()) {
80 registerExtensionPoint(registrar
, point
, psiManager
, prefix
, pluginId
);
85 private static void registerExtensionPoint(final DomExtensionsRegistrar registrar
, final ExtensionPoint extensionPoint
, final PsiManager manager
, String prefix
, @Nullable String pluginId
) {
86 String epName
= extensionPoint
.getName().getStringValue();
87 if (epName
!= null && StringUtil
.isNotEmpty(pluginId
)) epName
= pluginId
+ "." + epName
;
88 if (epName
== null) epName
= extensionPoint
.getQualifiedName().getStringValue();
89 if (epName
== null) return;
90 if (!epName
.startsWith(prefix
)) return;
92 final DomExtension domExtension
= registrar
.registerCollectionChildrenExtension(new XmlName(epName
.substring(prefix
.length())), Extension
.class);
93 domExtension
.putUserData(DomExtension
.KEY_DECLARATION
, extensionPoint
);
94 domExtension
.addExtender(new DomExtender() {
95 public void registerExtensions(@NotNull final DomElement domElement
, @NotNull final DomExtensionsRegistrar registrar
) {
96 final String interfaceName
= extensionPoint
.getInterface().getStringValue();
97 if (interfaceName
!= null) {
98 registrar
.registerGenericAttributeValueChildExtension(new XmlName("implementation"), PsiClass
.class).setConverter(
101 final PsiClass implClass
=
102 JavaPsiFacade
.getInstance(manager
.getProject()).findClass(interfaceName
, GlobalSearchScope
.allScope(manager
.getProject()));
103 if (implClass
!= null) {
104 registerXmlb(registrar
, implClass
);
108 final String beanClassName
= extensionPoint
.getBeanClass().getStringValue();
109 if (beanClassName
!= null) {
110 final PsiClass beanClass
=
111 JavaPsiFacade
.getInstance(manager
.getProject()).findClass(beanClassName
, GlobalSearchScope
.allScope(manager
.getProject()));
113 if (beanClass
!= null) {
114 registerXmlb(registrar
, beanClass
);
122 private static void registerXmlb(final DomExtensionsRegistrar registrar
, final PsiClass beanClass
) {
123 final PsiField
[] fields
= beanClass
.getAllFields();
124 for (PsiField field
: fields
) {
125 if (field
.hasModifierProperty(PsiModifier
.PUBLIC
)) {
126 registerField(registrar
, field
);
131 private static void registerField(final DomExtensionsRegistrar registrar
, @NotNull final PsiField field
) {
132 final PsiAnnotation
[] annotations
= field
.getModifierList().getAnnotations();
133 final PsiConstantEvaluationHelper evalHelper
= JavaPsiFacade
.getInstance(field
.getProject()).getConstantEvaluationHelper();
134 for (PsiAnnotation annotation
: annotations
) {
135 final String qName
= annotation
.getQualifiedName();
137 if (qName
.equals(Attribute
.class.getName())) {
138 final PsiAnnotationMemberValue attributeName
= annotation
.findAttributeValue("value");
139 if (attributeName
!= null && attributeName
instanceof PsiExpression
) {
140 final Class
<String
> type
= String
.class;
141 PsiExpression expression
= (PsiExpression
)attributeName
;
142 final Object evaluatedExpression
= evalHelper
.computeConstantExpression(expression
, false);
143 if (evaluatedExpression
!= null) {
144 registrar
.registerGenericAttributeValueChildExtension(new XmlName(evaluatedExpression
.toString()), type
);
147 } else if (qName
.equals(Tag
.class.getName())) {
148 final PsiAnnotationMemberValue attributeName
= annotation
.findAttributeValue("value");
149 if (attributeName
!= null && attributeName
instanceof PsiExpression
) {
150 PsiExpression expression
= (PsiExpression
)attributeName
;
151 final Object evaluatedExpression
= evalHelper
.computeConstantExpression(expression
, false);
152 if (evaluatedExpression
!= null) {
153 // I guess this actually needs something like registrar.registerGenericTagValueChildExtension...
154 registrar
.registerFixedNumberChildExtension(new XmlName(evaluatedExpression
.toString()), SimpleTagValue
.class);
162 public static Collection
<String
> getDependencies(IdeaPlugin ideaPlugin
) {
163 Set
<String
> result
= new HashSet
<String
>();
165 result
.add(PluginManager
.CORE_PLUGIN_ID
);
167 for (Dependency dependency
: ideaPlugin
.getDependencies()) {
168 ContainerUtil
.addIfNotNull(dependency
.getStringValue(), result
);
171 if (ideaPlugin
.getPluginId() == null) {
172 final VirtualFile file
= DomUtil
.getFile(ideaPlugin
).getOriginalFile().getVirtualFile();
174 final String fileName
= file
.getName();
175 if (!"plugin.xml".equals(fileName
)) {
176 final VirtualFile mainPluginXml
= file
.findFileByRelativePath("../plugin.xml");
177 if (mainPluginXml
!= null) {
178 final PsiFile psiFile
= PsiManager
.getInstance(ideaPlugin
.getManager().getProject()).findFile(mainPluginXml
);
179 if (psiFile
instanceof XmlFile
) {
180 final XmlFile xmlFile
= (XmlFile
)psiFile
;
181 final DomFileElement
<IdeaPlugin
> fileElement
= ideaPlugin
.getManager().getFileElement(xmlFile
, IdeaPlugin
.class);
182 if (fileElement
!= null) {
183 final IdeaPlugin mainPlugin
= fileElement
.getRootElement();
184 ContainerUtil
.addIfNotNull(mainPlugin
.getPluginId(), result
);
185 for (Dependency dependency
: mainPlugin
.getDependencies()) {
186 ContainerUtil
.addIfNotNull(dependency
.getStringValue(), result
);
198 interface SimpleTagValue
extends DomElement
{