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
.util
.Comparing
;
19 import com
.intellij
.openapi
.util
.Factory
;
20 import com
.intellij
.util
.containers
.ContainerUtil
;
21 import com
.intellij
.util
.xml
.DomElement
;
22 import com
.intellij
.util
.xml
.MergedObject
;
23 import com
.intellij
.util
.xml
.StableElement
;
24 import net
.sf
.cglib
.proxy
.InvocationHandler
;
25 import net
.sf
.cglib
.proxy
.AdvancedProxy
;
27 import java
.lang
.reflect
.InvocationTargetException
;
28 import java
.lang
.reflect
.Method
;
29 import java
.util
.Arrays
;
30 import java
.util
.HashSet
;
36 class StableInvocationHandler
<T
extends DomElement
> implements InvocationHandler
, StableElement
{
38 private T myCachedValue
;
39 private final Set
<Class
> myClasses
;
40 private final Factory
<T
> myProvider
;
42 public StableInvocationHandler(final T initial
, final Factory
<T
> provider
) {
43 myProvider
= provider
;
44 myCachedValue
= initial
;
46 final Class superClass
= initial
.getClass().getSuperclass();
47 final Set
<Class
> classes
= new HashSet
<Class
>();
48 classes
.addAll(Arrays
.asList(initial
.getClass().getInterfaces()));
49 ContainerUtil
.addIfNotNull(superClass
, classes
);
50 classes
.remove(MergedObject
.class);
55 public final Object
invoke(Object proxy
, final Method method
, final Object
[] args
) throws Throwable
{
56 if (StableElement
.class.equals(method
.getDeclaringClass())) {
58 return method
.invoke(this, args
);
60 catch (InvocationTargetException e
) {
65 if (AdvancedProxy
.FINALIZE_METHOD
.equals(method
)) return null;
67 if (isNotValid(myCachedValue
)) {
68 if (myCachedValue
!= null) {
69 myOldValue
= myCachedValue
;
71 myCachedValue
= myProvider
.create();
72 if (isNotValid(myCachedValue
)) {
73 if (AdvancedProxy
.EQUALS_METHOD
.equals(method
)) {
75 final Object arg
= args
[0];
76 if (!(arg
instanceof StableElement
)) return false;
78 final StableInvocationHandler handler
= DomManagerImpl
.getStableInvocationHandler(arg
);
79 if (handler
== null || handler
.getWrappedElement() != null) return false;
81 return Comparing
.equal(myOldValue
, handler
.myOldValue
);
84 if (myOldValue
!= null && Object
.class.equals(method
.getDeclaringClass())) {
85 return method
.invoke(myOldValue
, args
);
88 if ("isValid".equals(method
.getName())) {
91 throw new AssertionError("Calling methods on invalid value");
95 if (AdvancedProxy
.EQUALS_METHOD
.equals(method
)) {
96 final Object arg
= args
[0];
97 if (arg
instanceof StableElement
) {
98 return myCachedValue
.equals(((StableElement
)arg
).getWrappedElement());
100 return myCachedValue
.equals(arg
);
103 if (AdvancedProxy
.HASHCODE_METHOD
.equals(method
)) {
104 return myCachedValue
.hashCode();
108 return method
.invoke(myCachedValue
, args
);
110 catch (InvocationTargetException e
) {
115 public final void revalidate() {
116 final T t
= myProvider
.create();
117 if (!isNotValid(t
) && !t
.equals(myCachedValue
)) {
122 public final void invalidate() {
123 if (!isNotValid(myCachedValue
)) {
124 myCachedValue
= null;
128 public final DomElement
getWrappedElement() {
129 if (isNotValid(myCachedValue
)) {
130 myCachedValue
= myProvider
.create();
132 return myCachedValue
;
135 public T
getOldValue() {
139 private boolean isNotValid(final T t
) {
140 if (t
== null || !t
.isValid()) return true;
141 for (final Class aClass
: myClasses
) {
142 if (!aClass
.isInstance(t
)) return true;