update copyright
[fedora-idea.git] / xml / dom-impl / src / com / intellij / util / xml / impl / DynamicGenericInfo.java
blobdc2189e6b8a1c2129a18d1abe462b0df9fcae2ac
1 /*
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;
40 import java.util.Set;
42 /**
43 * @author peter
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;
59 myProject = project;
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);
80 try {
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)));
110 clearSubTags = true;
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)));
118 clearSubTags = true;
119 myCollections = newCollections;
122 final DomExtensionImpl extension = registrar.getCustomChildrenType();
123 if (extension != null) {
124 myCustomChildren = new CustomDomChildrenDescriptionImpl(null, extension.getType());
125 clearSubTags = true;
128 if (clearSubTags) {
129 for (XmlTag tag : ((XmlTag)element).getSubTags()) {
130 semService.clearCachedSemElements(tag);
135 myInitialized = true;
138 finally {
139 myComputing.set(null);
141 return true;
144 @Nullable
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);
162 return registrar;
165 public XmlElement getNameElement(DomElement element) {
166 return myStaticGenericInfo.getNameElement(element);
169 public GenericDomValue getNameDomElement(DomElement element) {
170 return myStaticGenericInfo.getNameDomElement(element);
173 @Nullable
174 public CustomDomChildrenDescriptionImpl getCustomNameChildrenDescription() {
175 checkInitialized();
176 if (myCustomChildren != null) return myCustomChildren;
177 return myStaticGenericInfo.getCustomNameChildrenDescription();
180 public String getElementName(DomElement element) {
181 return myStaticGenericInfo.getElementName(element);
184 @NotNull
185 public List<AbstractDomChildDescriptionImpl> getChildrenDescriptions() {
186 checkInitialized();
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);
192 return list;
195 @NotNull
196 public final List<FixedChildDescriptionImpl> getFixedChildrenDescriptions() {
197 checkInitialized();
198 return myFixeds.getDescriptions();
201 @NotNull
202 public final List<CollectionChildDescriptionImpl> getCollectionChildrenDescriptions() {
203 checkInitialized();
204 return myCollections.getDescriptions();
207 public FixedChildDescriptionImpl getFixedChildDescription(String tagName) {
208 checkInitialized();
209 return myFixeds.findDescription(tagName);
212 public DomFixedChildDescription getFixedChildDescription(@NonNls String tagName, @NonNls String namespace) {
213 checkInitialized();
214 return myFixeds.getDescription(tagName, namespace);
217 public CollectionChildDescriptionImpl getCollectionChildDescription(String tagName) {
218 checkInitialized();
219 return myCollections.findDescription(tagName);
222 public DomCollectionChildDescription getCollectionChildDescription(@NonNls String tagName, @NonNls String namespace) {
223 checkInitialized();
224 return myCollections.getDescription(tagName, namespace);
227 public AttributeChildDescriptionImpl getAttributeChildDescription(String attributeName) {
228 checkInitialized();
229 return myAttributes.findDescription(attributeName);
233 public DomAttributeChildDescription getAttributeChildDescription(@NonNls String attributeName, @NonNls String namespace) {
234 checkInitialized();
235 return myAttributes.getDescription(attributeName, namespace);
238 public Type[] getConcreteInterfaceVariants() {
239 return myStaticGenericInfo.getConcreteInterfaceVariants();
242 public boolean isTagValueElement() {
243 return myStaticGenericInfo.isTagValueElement();
246 @NotNull
247 public List<AttributeChildDescriptionImpl> getAttributeChildrenDescriptions() {
248 checkInitialized();
249 return myAttributes.getDescriptions();
252 @Override
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);
260 })) {
261 return false;
263 for (final AttributeChildDescriptionImpl description : getAttributeChildrenDescriptions()) {
264 if (!visited.contains(description) && !processor.process(description)) {
265 return false;
268 return true;