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 com
.intellij
.util
.xml
.impl
;
18 import com
.intellij
.openapi
.extensions
.Extensions
;
19 import com
.intellij
.openapi
.project
.Project
;
20 import com
.intellij
.psi
.xml
.XmlElement
;
21 import com
.intellij
.psi
.xml
.XmlTag
;
22 import com
.intellij
.psi
.xml
.XmlAttribute
;
23 import com
.intellij
.util
.ArrayUtil
;
24 import com
.intellij
.util
.Processor
;
25 import com
.intellij
.util
.containers
.ContainerUtil
;
26 import com
.intellij
.util
.xml
.DomElement
;
27 import com
.intellij
.util
.xml
.GenericDomValue
;
28 import com
.intellij
.util
.xml
.JavaMethod
;
29 import com
.intellij
.util
.xml
.reflect
.*;
30 import com
.intellij
.semantic
.SemService
;
31 import gnu
.trove
.THashSet
;
32 import org
.jetbrains
.annotations
.NonNls
;
33 import org
.jetbrains
.annotations
.NotNull
;
34 import org
.jetbrains
.annotations
.Nullable
;
36 import java
.lang
.reflect
.Type
;
37 import java
.util
.ArrayList
;
38 import java
.util
.Collections
;
39 import java
.util
.List
;
45 public class DynamicGenericInfo
extends DomGenericInfoEx
{
46 private final StaticGenericInfo myStaticGenericInfo
;
47 @NotNull private final DomInvocationHandler myInvocationHandler
;
48 private final Project myProject
;
49 private final ThreadLocal
<Boolean
> myComputing
= new ThreadLocal
<Boolean
>();
50 private volatile boolean myInitialized
;
51 private volatile ChildrenDescriptionsHolder
<AttributeChildDescriptionImpl
> myAttributes
;
52 private volatile ChildrenDescriptionsHolder
<FixedChildDescriptionImpl
> myFixeds
;
53 private volatile ChildrenDescriptionsHolder
<CollectionChildDescriptionImpl
> myCollections
;
54 private volatile CustomDomChildrenDescriptionImpl myCustomChildren
;
56 public DynamicGenericInfo(@NotNull final DomInvocationHandler handler
, final StaticGenericInfo staticGenericInfo
, final Project project
) {
57 myInvocationHandler
= handler
;
58 myStaticGenericInfo
= staticGenericInfo
;
61 myAttributes
= staticGenericInfo
.getAttributes();
62 myFixeds
= staticGenericInfo
.getFixed();
63 myCollections
= staticGenericInfo
.getCollections();
66 public Invocation
createInvocation(final JavaMethod method
) {
67 return myStaticGenericInfo
.createInvocation(method
);
70 public final boolean checkInitialized() {
71 if (myInitialized
) return true;
72 myStaticGenericInfo
.buildMethodMaps();
74 if (myComputing
.get() == Boolean
.TRUE
) return false;
76 final XmlElement element
= myInvocationHandler
.getXmlElement();
77 if (element
== null) return true;
79 myComputing
.set(Boolean
.TRUE
);
81 DomExtensionsRegistrarImpl registrar
= runDomExtenders();
83 synchronized (element
) {
84 if (myInitialized
) return true;
87 if (registrar
!= null) {
88 final SemService semService
= SemService
.getSemService(myProject
);
90 final List
<DomExtensionImpl
> fixeds
= registrar
.getFixeds();
91 final List
<DomExtensionImpl
> collections
= registrar
.getCollections();
92 final List
<DomExtensionImpl
> attributes
= registrar
.getAttributes();
93 if (!attributes
.isEmpty()) {
94 ChildrenDescriptionsHolder
<AttributeChildDescriptionImpl
> newAttributes
= new ChildrenDescriptionsHolder
<AttributeChildDescriptionImpl
>(myStaticGenericInfo
.getAttributes());
95 for (final DomExtensionImpl extension
: attributes
) {
96 newAttributes
.addDescription(extension
.addAnnotations(new AttributeChildDescriptionImpl(extension
.getXmlName(), extension
.getType())));
98 for (XmlAttribute attribute
: ((XmlTag
)element
).getAttributes()) {
99 semService
.clearCachedSemElements(attribute
);
101 myAttributes
= newAttributes
;
104 boolean clearSubTags
= false;
105 if (!fixeds
.isEmpty()) {
106 ChildrenDescriptionsHolder
<FixedChildDescriptionImpl
> newFixeds
= new ChildrenDescriptionsHolder
<FixedChildDescriptionImpl
>(myStaticGenericInfo
.getFixed());
107 for (final DomExtensionImpl extension
: fixeds
) {
108 newFixeds
.addDescription(extension
.addAnnotations(new FixedChildDescriptionImpl(extension
.getXmlName(), extension
.getType(), extension
.getCount(), ArrayUtil
.EMPTY_COLLECTION_ARRAY
)));
111 myFixeds
= newFixeds
;
113 if (!collections
.isEmpty()) {
114 ChildrenDescriptionsHolder
<CollectionChildDescriptionImpl
> newCollections
= new ChildrenDescriptionsHolder
<CollectionChildDescriptionImpl
>(myStaticGenericInfo
.getCollections());
115 for (final DomExtensionImpl extension
: collections
) {
116 newCollections
.addDescription(extension
.addAnnotations(new CollectionChildDescriptionImpl(extension
.getXmlName(), extension
.getType(), Collections
.EMPTY_LIST
, Collections
.EMPTY_LIST
, Collections
.EMPTY_LIST
, Collections
.EMPTY_LIST
, Collections
.EMPTY_LIST
, Collections
.EMPTY_LIST
)));
119 myCollections
= newCollections
;
122 final DomExtensionImpl extension
= registrar
.getCustomChildrenType();
123 if (extension
!= null) {
124 myCustomChildren
= new CustomDomChildrenDescriptionImpl(null, extension
.getType());
129 for (XmlTag tag
: ((XmlTag
)element
).getSubTags()) {
130 semService
.clearCachedSemElements(tag
);
135 myInitialized
= true;
139 myComputing
.set(null);
145 private DomExtensionsRegistrarImpl
runDomExtenders() {
146 DomExtensionsRegistrarImpl registrar
= null;
147 final DomElement domElement
= myInvocationHandler
.getProxy();
148 for (final DomExtenderEP extenderEP
: Extensions
.getExtensions(DomExtenderEP
.EP_NAME
)) {
149 registrar
= extenderEP
.extend(myProject
, domElement
, registrar
);
152 final AbstractDomChildDescriptionImpl description
= myInvocationHandler
.getChildDescription();
153 if (description
!= null) {
154 final List
<DomExtender
> extenders
= description
.getUserData(DomExtensionImpl
.DOM_EXTENDER_KEY
);
155 if (extenders
!= null) {
156 if (registrar
== null) registrar
= new DomExtensionsRegistrarImpl();
157 for (final DomExtender extender
: extenders
) {
158 extender
.registerExtensions(domElement
, registrar
);
165 public XmlElement
getNameElement(DomElement element
) {
166 return myStaticGenericInfo
.getNameElement(element
);
169 public GenericDomValue
getNameDomElement(DomElement element
) {
170 return myStaticGenericInfo
.getNameDomElement(element
);
174 public CustomDomChildrenDescriptionImpl
getCustomNameChildrenDescription() {
176 if (myCustomChildren
!= null) return myCustomChildren
;
177 return myStaticGenericInfo
.getCustomNameChildrenDescription();
180 public String
getElementName(DomElement element
) {
181 return myStaticGenericInfo
.getElementName(element
);
185 public List
<AbstractDomChildDescriptionImpl
> getChildrenDescriptions() {
187 final ArrayList
<AbstractDomChildDescriptionImpl
> list
= new ArrayList
<AbstractDomChildDescriptionImpl
>();
188 list
.addAll(myAttributes
.getDescriptions());
189 list
.addAll(myFixeds
.getDescriptions());
190 list
.addAll(myCollections
.getDescriptions());
191 ContainerUtil
.addIfNotNull(myStaticGenericInfo
.getCustomNameChildrenDescription(), list
);
196 public final List
<FixedChildDescriptionImpl
> getFixedChildrenDescriptions() {
198 return myFixeds
.getDescriptions();
202 public final List
<CollectionChildDescriptionImpl
> getCollectionChildrenDescriptions() {
204 return myCollections
.getDescriptions();
207 public FixedChildDescriptionImpl
getFixedChildDescription(String tagName
) {
209 return myFixeds
.findDescription(tagName
);
212 public DomFixedChildDescription
getFixedChildDescription(@NonNls String tagName
, @NonNls String namespace
) {
214 return myFixeds
.getDescription(tagName
, namespace
);
217 public CollectionChildDescriptionImpl
getCollectionChildDescription(String tagName
) {
219 return myCollections
.findDescription(tagName
);
222 public DomCollectionChildDescription
getCollectionChildDescription(@NonNls String tagName
, @NonNls String namespace
) {
224 return myCollections
.getDescription(tagName
, namespace
);
227 public AttributeChildDescriptionImpl
getAttributeChildDescription(String attributeName
) {
229 return myAttributes
.findDescription(attributeName
);
233 public DomAttributeChildDescription
getAttributeChildDescription(@NonNls String attributeName
, @NonNls String namespace
) {
235 return myAttributes
.getDescription(attributeName
, namespace
);
238 public Type
[] getConcreteInterfaceVariants() {
239 return myStaticGenericInfo
.getConcreteInterfaceVariants();
242 public boolean isTagValueElement() {
243 return myStaticGenericInfo
.isTagValueElement();
247 public List
<AttributeChildDescriptionImpl
> getAttributeChildrenDescriptions() {
249 return myAttributes
.getDescriptions();
253 public boolean processAttributeChildrenDescriptions(final Processor
<AttributeChildDescriptionImpl
> processor
) {
254 final Set
<AttributeChildDescriptionImpl
> visited
= new THashSet
<AttributeChildDescriptionImpl
>();
255 if (!myStaticGenericInfo
.processAttributeChildrenDescriptions(new Processor
<AttributeChildDescriptionImpl
>() {
256 public boolean process(AttributeChildDescriptionImpl attributeChildDescription
) {
257 visited
.add(attributeChildDescription
);
258 return processor
.process(attributeChildDescription
);
263 for (final AttributeChildDescriptionImpl description
: getAttributeChildrenDescriptions()) {
264 if (!visited
.contains(description
) && !processor
.process(description
)) {