update copyright
[fedora-idea.git] / xml / dom-impl / src / com / intellij / util / xml / impl / StableInvocationHandler.java
blob48a5ce1cc8c4685e4f360cea691a3da93e13b113
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.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;
31 import java.util.Set;
33 /**
34 * @author peter
36 class StableInvocationHandler<T extends DomElement> implements InvocationHandler, StableElement {
37 private T myOldValue;
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;
45 myOldValue = 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);
51 myClasses = classes;
55 public final Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
56 if (StableElement.class.equals(method.getDeclaringClass())) {
57 try {
58 return method.invoke(this, args);
60 catch (InvocationTargetException e) {
61 throw e.getCause();
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())) {
89 return Boolean.FALSE;
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();
107 try {
108 return method.invoke(myCachedValue, args);
110 catch (InvocationTargetException e) {
111 throw e.getCause();
115 public final void revalidate() {
116 final T t = myProvider.create();
117 if (!isNotValid(t) && !t.equals(myCachedValue)) {
118 myCachedValue = t;
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() {
136 return myOldValue;
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;
144 return false;