KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > proxy > ProxyDelegationStrategy


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.aspectwerkz.proxy;
5
6
7 import com.tc.aspectwerkz.definition.SystemDefinition;
8 import com.tc.aspectwerkz.definition.SystemDefinitionContainer;
9 import com.tc.aspectwerkz.exception.WrappedRuntimeException;
10
11 import java.lang.reflect.InvocationTargetException JavaDoc;
12 import java.util.Arrays JavaDoc;
13 import java.util.Map JavaDoc;
14 import java.util.WeakHashMap JavaDoc;
15
16 /**
17  * Get proxy classes from target classes that implement target interfaces and weaves in all matching aspects deployed in
18  * the class loader and defined by the <code>META-INF/aop.xml</code> file.
19  *
20  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
21  * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr</a>
22  */

23 public class ProxyDelegationStrategy {
24
25   /**
26    * Suffix for proxy class name. A UUID is further suffixed.
27    */

28   public static final String JavaDoc PROXY_SUFFIX = "$$ProxiedByAWDelegation$$";
29
30   /**
31    * Cache for the compiled proxy classes. Implemented interfaces classes are composite key.
32    */

33   private final static Map JavaDoc PROXY_CLASS_CACHE = new WeakHashMap JavaDoc();
34
35   /**
36    * Compile or retrieve from cache a delegation proxy for the given interfaces.
37    *
38    * @param proxyName
39    * @param interfaces
40    * @param useCache
41    * @param makeAdvisable
42    * @return
43    */

44   static Class JavaDoc getProxyClassFor(String JavaDoc proxyName,
45                                 Class JavaDoc[] interfaces,
46                                 boolean useCache,
47                                 boolean makeAdvisable,
48                                 final SystemDefinition definition) {
49     final Class JavaDoc proxyClass;
50     if (!useCache) {
51       proxyClass = getNewProxyClassFor(
52           proxyName,
53           interfaces,
54           makeAdvisable,
55           definition);
56     } else {
57       CompositeClassKey key = new CompositeClassKey(interfaces);
58       synchronized (PROXY_CLASS_CACHE) {
59         Object JavaDoc cachedProxyClass = PROXY_CLASS_CACHE.get(key);
60         if (cachedProxyClass != null) {
61           return (Class JavaDoc) cachedProxyClass;
62         }
63         proxyClass = getNewProxyClassFor(
64                 proxyName,
65                 interfaces,
66                 makeAdvisable,
67                 definition);
68         PROXY_CLASS_CACHE.put(key, proxyClass);
69       }
70     }
71     ProxyCompilerHelper.compileJoinPoint(proxyClass, definition);
72     return proxyClass;
73  }
74
75   /**
76    * Create a delegation proxy or retrieve it from cache and instantiate it, using the given implementations. <p/> Each
77    * implementation must implement the respective given interface.
78    *
79    * @param interfaces
80    * @param implementations
81    * @param useCache
82    * @param makeAdvisable
83    * @return
84    */

85   static Object JavaDoc newInstance(final Class JavaDoc[] interfaces,
86                             final Object JavaDoc[] implementations,
87                             final boolean useCache,
88                             final boolean makeAdvisable,
89                             final SystemDefinition definition) {
90     if (!implementsRespectively(interfaces, implementations)) {
91       throw new RuntimeException JavaDoc(
92               "Given implementations not consistents with given interfaces");
93     }
94     Class JavaDoc proxy = getProxyClassFor(
95             definition.getUuid(),
96             interfaces,
97             useCache,
98             makeAdvisable,
99             definition
100     );
101     try {
102       return proxy.getConstructor(interfaces).newInstance(implementations);
103     } catch (InvocationTargetException JavaDoc t) {
104       throw new WrappedRuntimeException(t.getCause());
105     } catch (Throwable JavaDoc t) {
106       throw new WrappedRuntimeException(t);
107     }
108   }
109
110   /**
111    * Return true if each implementation implement the respective given interface.
112    *
113    * @param interfaces
114    * @param implementations
115    * @return
116    */

117   private static boolean implementsRespectively(final Class JavaDoc[] interfaces,
118                                                 final Object JavaDoc[] implementations) {
119     if (interfaces.length != implementations.length) {
120       return false;
121     }
122     for (int i = 0; i < interfaces.length; i++) {
123       if (!interfaces[i].isAssignableFrom(implementations[i].getClass())) {
124         return false;
125       }
126     }
127     return true;
128   }
129
130   /**
131    * Compile a new proxy class and attach it to the lowest shared classloader of the given interfaces (as for JDK
132    * proxy).
133    *
134    * @param proxyName
135    * @param interfaces
136    * @param makeAdvisable
137    * @return
138    */

139   private static Class JavaDoc getNewProxyClassFor(String JavaDoc proxyName,
140                                            Class JavaDoc[] interfaces,
141                                            boolean makeAdvisable,
142                                            final SystemDefinition definition) {
143     ClassLoader JavaDoc loader = getLowestClassLoader(interfaces);
144     if (makeAdvisable) {
145       Proxy.makeProxyAdvisable(proxyName, loader, definition);
146     }
147     final byte[] bytes = ProxyDelegationCompiler.compileProxyFor(loader, interfaces, proxyName);
148     return ProxyCompilerHelper.weaveAndDefineProxyClass(
149             bytes,
150             loader,
151             proxyName,
152             definition
153     );
154   }
155
156   /**
157    * Returns the lowest (childest) shared classloader or fail it detects parallel hierarchies.
158    *
159    * @param classes
160    * @return
161    */

162   private static ClassLoader JavaDoc getLowestClassLoader(Class JavaDoc[] classes) {
163     ClassLoader JavaDoc loader = classes[0].getClassLoader();
164     for (int i = 1; i < classes.length; i++) {
165       Class JavaDoc other = classes[i];
166       if (SystemDefinitionContainer.isChildOf(other.getClassLoader(), loader)) {
167         loader = other.getClassLoader();
168       } else if (SystemDefinitionContainer.isChildOf(loader, other.getClassLoader())) {
169         ;// loader is fine
170
} else {
171         throw new RuntimeException JavaDoc("parallel classloader hierarchy not supported");
172       }
173     }
174     return loader;
175   }
176
177   /**
178    * A composite key for the proxy cache.
179    */

180   private static class CompositeClassKey {
181     private final Class JavaDoc[] m_interfaces;
182
183     CompositeClassKey(Class JavaDoc[] interfaces) {
184       m_interfaces = interfaces;
185     }
186
187     public boolean equals(Object JavaDoc o) {
188       if (this == o) return true;
189       if (!(o instanceof CompositeClassKey)) return false;
190
191       final CompositeClassKey compositeClassKey = (CompositeClassKey) o;
192
193       if (!Arrays.equals(m_interfaces, compositeClassKey.m_interfaces)) return false;
194
195       return true;
196     }
197
198     public int hashCode() {
199       int result = 1;
200       for (int i = 0; i < m_interfaces.length; i++) {
201         result = 31 * result + m_interfaces[i].hashCode();
202       }
203       return result;
204     }
205   }
206
207 }
208
Popular Tags