API for lazy registration of metadata; some related refactoring
[fedora-idea.git] / lang-impl / src / com / intellij / psi / impl / meta / MetaRegistry.java
blob8733382dbc867a01ab5cf315bb6552ec0d127675
1 package com.intellij.psi.impl.meta;
3 import com.intellij.openapi.Disposable;
4 import com.intellij.openapi.extensions.Extensions;
5 import com.intellij.openapi.progress.ProgressManager;
6 import com.intellij.openapi.util.Disposer;
7 import com.intellij.openapi.util.Key;
8 import com.intellij.openapi.util.UserDataCache;
9 import com.intellij.psi.PsiElement;
10 import com.intellij.psi.filters.ElementFilter;
11 import com.intellij.psi.meta.MetaDataRegistrar;
12 import com.intellij.psi.meta.PsiMetaData;
13 import com.intellij.psi.meta.MetaDataContributor;
14 import com.intellij.psi.util.CachedValue;
15 import com.intellij.psi.util.CachedValueProvider;
16 import org.jetbrains.annotations.NotNull;
17 import org.jetbrains.annotations.Nullable;
19 import java.util.ArrayList;
20 import java.util.List;
22 /**
23 * Created by IntelliJ IDEA.
24 * User: ik
25 * Date: 07.05.2003
26 * Time: 3:31:09
27 * To change this template use Options | File Templates.
29 public class MetaRegistry extends MetaDataRegistrar {
30 private static final List<MyBinding> ourBindings = new ArrayList<MyBinding>();
31 private static boolean ourContributorsLoaded = false;
33 private static final Key<CachedValue<PsiMetaData>> META_DATA_KEY = Key.create("META DATA KEY");
35 public static void bindDataToElement(final PsiElement element, final PsiMetaData data){
36 CachedValue<PsiMetaData> value =
37 element.getManager().getCachedValuesManager().createCachedValue(new CachedValueProvider<PsiMetaData>() {
38 public Result<PsiMetaData> compute() {
39 data.init(element);
40 return new Result<PsiMetaData>(data, data.getDependences());
42 });
43 element.putUserData(META_DATA_KEY, value);
46 public static PsiMetaData getMeta(final PsiElement element) {
47 final PsiMetaData base = getMetaBase(element);
48 return base != null ? base : null;
51 private static UserDataCache<CachedValue<PsiMetaData>, PsiElement, Object> ourCachedMetaCache =
52 new UserDataCache<CachedValue<PsiMetaData>, PsiElement, Object>() {
53 protected CachedValue<PsiMetaData> compute(final PsiElement element, Object p) {
54 return element.getManager().getCachedValuesManager()
55 .createCachedValue(new CachedValueProvider<PsiMetaData>() {
56 public Result<PsiMetaData> compute() {
57 try {
58 ensureContributorsLoaded();
59 for (final MyBinding binding : ourBindings) {
60 if (binding.myFilter.isClassAcceptable(element.getClass()) && binding.myFilter.isAcceptable(element, element.getParent())) {
61 final PsiMetaData data = binding.myDataClass.newInstance();
62 data.init(element);
63 return new Result<PsiMetaData>(data, data.getDependences());
66 } catch (IllegalAccessException iae) {
67 throw new RuntimeException(iae);
69 catch (InstantiationException ie) {
70 throw new RuntimeException(ie);
73 return new Result<PsiMetaData>(null, element);
75 }, false);
79 private static void ensureContributorsLoaded() {
80 if (!ourContributorsLoaded) {
81 ourContributorsLoaded = true;
82 for(MetaDataContributor contributor: Extensions.getExtensions(MetaDataContributor.EP_NAME)) {
83 contributor.contributeMetaData(MetaDataRegistrar.getInstance());
88 @Nullable
89 public static PsiMetaData getMetaBase(final PsiElement element) {
90 ProgressManager.getInstance().checkCanceled();
91 return ourCachedMetaCache.get(META_DATA_KEY, element, null).getValue();
94 public static <T extends PsiMetaData> void addMetadataBinding(ElementFilter filter, Class<T> aMetadataClass, Disposable parentDisposable) {
95 final MyBinding binding = new MyBinding(filter, aMetadataClass);
96 addBinding(binding);
97 Disposer.register(parentDisposable, new Disposable() {
98 public void dispose() {
99 ourBindings.remove(binding);
104 public static <T extends PsiMetaData> void addMetadataBinding(ElementFilter filter, Class<T> aMetadataClass) {
105 addBinding(new MyBinding(filter, aMetadataClass));
108 private static void addBinding(final MyBinding binding) {
109 ourBindings.add(0, binding);
112 public <T extends PsiMetaData> void registerMetaData(ElementFilter filter, Class<T> metadataDescriptorClass) {
113 addMetadataBinding(filter, metadataDescriptorClass);
116 private static class MyBinding {
117 ElementFilter myFilter;
118 Class<PsiMetaData> myDataClass;
120 public <T extends PsiMetaData> MyBinding(@NotNull ElementFilter filter, @NotNull Class<T> dataClass) {
121 myFilter = filter;
122 myDataClass = (Class)dataClass;