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.
17 package com
.intellij
.psi
.impl
.meta
;
19 import com
.intellij
.openapi
.Disposable
;
20 import com
.intellij
.openapi
.extensions
.Extensions
;
21 import com
.intellij
.openapi
.progress
.ProgressManager
;
22 import com
.intellij
.openapi
.util
.Disposer
;
23 import com
.intellij
.openapi
.util
.Key
;
24 import com
.intellij
.openapi
.util
.UserDataCache
;
25 import com
.intellij
.patterns
.ElementPattern
;
26 import com
.intellij
.psi
.PsiElement
;
27 import com
.intellij
.psi
.util
.CachedValue
;
28 import com
.intellij
.psi
.util
.CachedValueProvider
;
29 import com
.intellij
.psi
.filters
.ElementFilter
;
30 import com
.intellij
.psi
.filters
.position
.PatternFilter
;
31 import com
.intellij
.psi
.meta
.MetaDataContributor
;
32 import com
.intellij
.psi
.meta
.MetaDataRegistrar
;
33 import com
.intellij
.psi
.meta
.PsiMetaData
;
34 import com
.intellij
.util
.containers
.ContainerUtil
;
35 import org
.jetbrains
.annotations
.NotNull
;
36 import org
.jetbrains
.annotations
.Nullable
;
38 import java
.util
.List
;
41 * Created by IntelliJ IDEA.
45 * To change this template use Options | File Templates.
47 public class MetaRegistry
extends MetaDataRegistrar
{
48 private static final List
<MyBinding
> ourBindings
= ContainerUtil
.createEmptyCOWList();
49 private static volatile boolean ourContributorsLoaded
= false;
51 private static final Key
<CachedValue
<PsiMetaData
>> META_DATA_KEY
= Key
.create("META DATA KEY");
53 public static void bindDataToElement(final PsiElement element
, final PsiMetaData data
) {
54 CachedValue
<PsiMetaData
> value
=
55 element
.getManager().getCachedValuesManager().createCachedValue(new CachedValueProvider
<PsiMetaData
>() {
56 public Result
<PsiMetaData
> compute() {
58 return new Result
<PsiMetaData
>(data
, data
.getDependences());
61 element
.putUserData(META_DATA_KEY
, value
);
64 public static PsiMetaData
getMeta(final PsiElement element
) {
65 final PsiMetaData base
= getMetaBase(element
);
66 return base
!= null ? base
: null;
69 private static final UserDataCache
<CachedValue
<PsiMetaData
>, PsiElement
, Object
> ourCachedMetaCache
=
70 new UserDataCache
<CachedValue
<PsiMetaData
>, PsiElement
, Object
>() {
71 protected CachedValue
<PsiMetaData
> compute(final PsiElement element
, Object p
) {
72 return element
.getManager().getCachedValuesManager()
73 .createCachedValue(new CachedValueProvider
<PsiMetaData
>() {
74 public Result
<PsiMetaData
> compute() {
76 ensureContributorsLoaded();
77 for (final MyBinding binding
: ourBindings
) {
78 if (binding
.myFilter
.isClassAcceptable(element
.getClass()) && binding
.myFilter
.isAcceptable(element
, element
.getParent())) {
79 final PsiMetaData data
= binding
.myDataClass
.newInstance();
81 return new Result
<PsiMetaData
>(data
, data
.getDependences());
85 catch (IllegalAccessException iae
) {
86 throw new RuntimeException(iae
);
88 catch (InstantiationException ie
) {
89 throw new RuntimeException(ie
);
92 return new Result
<PsiMetaData
>(null, element
);
98 private static void ensureContributorsLoaded() {
99 if (!ourContributorsLoaded
) {
100 synchronized (ourBindings
) {
101 if (!ourContributorsLoaded
) {
102 for(MetaDataContributor contributor
: Extensions
.getExtensions(MetaDataContributor
.EP_NAME
)) {
103 contributor
.contributeMetaData(MetaDataRegistrar
.getInstance());
105 ourContributorsLoaded
= true;
112 public static PsiMetaData
getMetaBase(final PsiElement element
) {
113 ProgressManager
.getInstance().checkCanceled();
114 return ourCachedMetaCache
.get(META_DATA_KEY
, element
, null).getValue();
117 public static <T
extends PsiMetaData
> void addMetadataBinding(ElementFilter filter
, Class
<T
> aMetadataClass
, Disposable parentDisposable
) {
118 final MyBinding binding
= new MyBinding(filter
, aMetadataClass
);
120 Disposer
.register(parentDisposable
, new Disposable() {
121 public void dispose() {
122 ourBindings
.remove(binding
);
127 public static <T
extends PsiMetaData
> void addMetadataBinding(ElementFilter filter
, Class
<T
> aMetadataClass
) {
128 addBinding(new MyBinding(filter
, aMetadataClass
));
131 private static void addBinding(final MyBinding binding
) {
132 ourBindings
.add(0, binding
);
135 public <T
extends PsiMetaData
> void registerMetaData(ElementFilter filter
, Class
<T
> metadataDescriptorClass
) {
136 addMetadataBinding(filter
, metadataDescriptorClass
);
140 public <T
extends PsiMetaData
> void registerMetaData(ElementPattern
<?
> pattern
, Class
<T
> metadataDescriptorClass
) {
141 addMetadataBinding(new PatternFilter(pattern
), metadataDescriptorClass
);
144 private static class MyBinding
{
145 private final ElementFilter myFilter
;
146 private final Class
<?
extends PsiMetaData
> myDataClass
;
148 public MyBinding(@NotNull ElementFilter filter
, @NotNull Class
<?
extends PsiMetaData
> dataClass
) {
150 myDataClass
= dataClass
;