blob: 061ab6ac83c42546714da3a1efba9c315feeddd8 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.xml.impl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.util.NotNullFunction;
import com.intellij.util.ReflectionAssignabilityCache;
import com.intellij.util.containers.ConcurrentFactoryMap;
import com.intellij.util.containers.FactoryMap;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.DomElementVisitor;
import com.intellij.util.xml.DomFileDescription;
import com.intellij.util.xml.TypeChooserManager;
import com.intellij.util.xml.highlighting.DomElementsAnnotator;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.intellij.util.containers.ContainerUtil.newArrayList;
/**
* @author peter
*/
public class DomApplicationComponent {
private final FactoryMap<String,Set<DomFileDescription>> myRootTagName2FileDescription = new FactoryMap<String, Set<DomFileDescription>>() {
@Override
protected Set<DomFileDescription> create(final String key) {
return new THashSet<DomFileDescription>();
}
};
private final Set<DomFileDescription> myAcceptingOtherRootTagNamesDescriptions = new THashSet<DomFileDescription>();
private final ImplementationClassCache myCachedImplementationClasses = new ImplementationClassCache(DomImplementationClassEP.EP_NAME);
private final TypeChooserManager myTypeChooserManager = new TypeChooserManager();
final ReflectionAssignabilityCache assignabilityCache = new ReflectionAssignabilityCache();
private final FactoryMap<Class, DomElementsAnnotator> myClass2Annotator = new ConcurrentFactoryMap<Class, DomElementsAnnotator>() {
@Override
protected DomElementsAnnotator create(Class key) {
final DomFileDescription desc = findFileDescription(key);
return desc == null ? null : desc.createAnnotator();
}
};
private final SofterCache<Type, StaticGenericInfo> myGenericInfos = SofterCache.create(new NotNullFunction<Type, StaticGenericInfo>() {
@NotNull
@Override
public StaticGenericInfo fun(Type type) {
return new StaticGenericInfo(type);
}
});
private final SofterCache<Class, InvocationCache> myInvocationCaches = SofterCache.create(new NotNullFunction<Class, InvocationCache>() {
@NotNull
@Override
public InvocationCache fun(Class key) {
return new InvocationCache(key);
}
});
private final ConcurrentFactoryMap<Class<? extends DomElementVisitor>, VisitorDescription> myVisitorDescriptions =
new ConcurrentFactoryMap<Class<? extends DomElementVisitor>, VisitorDescription>() {
@Override
@NotNull
protected VisitorDescription create(final Class<? extends DomElementVisitor> key) {
return new VisitorDescription(key);
}
};
public DomApplicationComponent() {
for (final DomFileDescription description : Extensions.getExtensions(DomFileDescription.EP_NAME)) {
registerFileDescription(description);
}
}
public static DomApplicationComponent getInstance() {
return ServiceManager.getService(DomApplicationComponent.class);
}
public int getCumulativeVersion() {
int result = 0;
for (DomFileDescription description : getAllFileDescriptions()) {
if (description.hasStubs()) {
result += description.getStubVersion();
result += description.getRootTagName().hashCode(); // so that a plugin enabling/disabling could trigger the reindexing
}
}
return result;
}
public final synchronized Set<DomFileDescription> getFileDescriptions(String rootTagName) {
return myRootTagName2FileDescription.get(rootTagName);
}
public final synchronized Set<DomFileDescription> getAcceptingOtherRootTagNameDescriptions() {
return myAcceptingOtherRootTagNamesDescriptions;
}
public final synchronized void registerFileDescription(final DomFileDescription description) {
myRootTagName2FileDescription.get(description.getRootTagName()).add(description);
if (description.acceptsOtherRootTagNames()) {
myAcceptingOtherRootTagNamesDescriptions.add(description);
}
//noinspection unchecked
final Map<Class<? extends DomElement>, Class<? extends DomElement>> implementations = description.getImplementations();
for (final Map.Entry<Class<? extends DomElement>, Class<? extends DomElement>> entry : implementations.entrySet()) {
registerImplementation(entry.getKey(), entry.getValue(), null);
}
myTypeChooserManager.copyFrom(description.getTypeChooserManager());
}
public synchronized List<DomFileDescription> getAllFileDescriptions() {
final List<DomFileDescription> result = newArrayList();
for (Set<DomFileDescription> descriptions : myRootTagName2FileDescription.values()) {
result.addAll(descriptions);
}
result.addAll(myAcceptingOtherRootTagNamesDescriptions);
return result;
}
@Nullable
private synchronized DomFileDescription findFileDescription(Class rootElementClass) {
for (Set<DomFileDescription> descriptions : myRootTagName2FileDescription.values()) {
for (DomFileDescription description : descriptions) {
if (description.getRootElementClass() == rootElementClass) {
return description;
}
}
}
for (DomFileDescription description : myAcceptingOtherRootTagNamesDescriptions) {
if (description.getRootElementClass() == rootElementClass) {
return description;
}
}
return null;
}
public DomElementsAnnotator getAnnotator(Class rootElementClass) {
return myClass2Annotator.get(rootElementClass);
}
@Nullable
final Class<? extends DomElement> getImplementation(final Class concreteInterface) {
//noinspection unchecked
return myCachedImplementationClasses.get(concreteInterface);
}
public final void registerImplementation(Class<? extends DomElement> domElementClass, Class<? extends DomElement> implementationClass,
@Nullable final Disposable parentDisposable) {
myCachedImplementationClasses.registerImplementation(domElementClass, implementationClass, parentDisposable);
}
public TypeChooserManager getTypeChooserManager() {
return myTypeChooserManager;
}
public final StaticGenericInfo getStaticGenericInfo(final Type type) {
return myGenericInfos.getCachedValue(type);
}
final InvocationCache getInvocationCache(final Class type) {
return myInvocationCaches.getCachedValue(type);
}
public final VisitorDescription getVisitorDescription(Class<? extends DomElementVisitor> aClass) {
return myVisitorDescriptions.get(aClass);
}
}