001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.proxy;
005:
006: import com.tc.aspectwerkz.definition.SystemDefinition;
007: import com.tc.aspectwerkz.definition.SystemDefinitionContainer;
008: import com.tc.aspectwerkz.exception.WrappedRuntimeException;
009:
010: import java.lang.reflect.InvocationTargetException;
011: import java.util.Arrays;
012: import java.util.Map;
013: import java.util.WeakHashMap;
014:
015: /**
016: * Get proxy classes from target classes that implement target interfaces and weaves in all matching aspects deployed in
017: * the class loader and defined by the <code>META-INF/aop.xml</code> file.
018: *
019: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
020: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr</a>
021: */
022: public class ProxyDelegationStrategy {
023:
024: /**
025: * Suffix for proxy class name. A UUID is further suffixed.
026: */
027: public static final String PROXY_SUFFIX = "$$ProxiedByAWDelegation$$";
028:
029: /**
030: * Cache for the compiled proxy classes. Implemented interfaces classes are composite key.
031: */
032: private final static Map PROXY_CLASS_CACHE = new WeakHashMap();
033:
034: /**
035: * Compile or retrieve from cache a delegation proxy for the given interfaces.
036: *
037: * @param proxyName
038: * @param interfaces
039: * @param useCache
040: * @param makeAdvisable
041: * @return
042: */
043: static Class getProxyClassFor(String proxyName, Class[] interfaces,
044: boolean useCache, boolean makeAdvisable,
045: final SystemDefinition definition) {
046: final Class proxyClass;
047: if (!useCache) {
048: proxyClass = getNewProxyClassFor(proxyName, interfaces,
049: makeAdvisable, definition);
050: } else {
051: CompositeClassKey key = new CompositeClassKey(interfaces);
052: synchronized (PROXY_CLASS_CACHE) {
053: Object cachedProxyClass = PROXY_CLASS_CACHE.get(key);
054: if (cachedProxyClass != null) {
055: return (Class) cachedProxyClass;
056: }
057: proxyClass = getNewProxyClassFor(proxyName, interfaces,
058: makeAdvisable, definition);
059: PROXY_CLASS_CACHE.put(key, proxyClass);
060: }
061: }
062: ProxyCompilerHelper.compileJoinPoint(proxyClass, definition);
063: return proxyClass;
064: }
065:
066: /**
067: * Create a delegation proxy or retrieve it from cache and instantiate it, using the given implementations. <p/> Each
068: * implementation must implement the respective given interface.
069: *
070: * @param interfaces
071: * @param implementations
072: * @param useCache
073: * @param makeAdvisable
074: * @return
075: */
076: static Object newInstance(final Class[] interfaces,
077: final Object[] implementations, final boolean useCache,
078: final boolean makeAdvisable,
079: final SystemDefinition definition) {
080: if (!implements Respectively(interfaces, implementations)) {
081: throw new RuntimeException(
082: "Given implementations not consistents with given interfaces");
083: }
084: Class proxy = getProxyClassFor(definition.getUuid(),
085: interfaces, useCache, makeAdvisable, definition);
086: try {
087: return proxy.getConstructor(interfaces).newInstance(
088: implementations);
089: } catch (InvocationTargetException t) {
090: throw new WrappedRuntimeException(t.getCause());
091: } catch (Throwable t) {
092: throw new WrappedRuntimeException(t);
093: }
094: }
095:
096: /**
097: * Return true if each implementation implement the respective given interface.
098: *
099: * @param interfaces
100: * @param implementations
101: * @return
102: */
103: private static boolean implements Respectively(
104: final Class[] interfaces, final Object[] implementations) {
105: if (interfaces.length != implementations.length) {
106: return false;
107: }
108: for (int i = 0; i < interfaces.length; i++) {
109: if (!interfaces[i].isAssignableFrom(implementations[i]
110: .getClass())) {
111: return false;
112: }
113: }
114: return true;
115: }
116:
117: /**
118: * Compile a new proxy class and attach it to the lowest shared classloader of the given interfaces (as for JDK
119: * proxy).
120: *
121: * @param proxyName
122: * @param interfaces
123: * @param makeAdvisable
124: * @return
125: */
126: private static Class getNewProxyClassFor(String proxyName,
127: Class[] interfaces, boolean makeAdvisable,
128: final SystemDefinition definition) {
129: ClassLoader loader = getLowestClassLoader(interfaces);
130: if (makeAdvisable) {
131: Proxy.makeProxyAdvisable(proxyName, loader, definition);
132: }
133: final byte[] bytes = ProxyDelegationCompiler.compileProxyFor(
134: loader, interfaces, proxyName);
135: return ProxyCompilerHelper.weaveAndDefineProxyClass(bytes,
136: loader, proxyName, definition);
137: }
138:
139: /**
140: * Returns the lowest (childest) shared classloader or fail it detects parallel hierarchies.
141: *
142: * @param classes
143: * @return
144: */
145: private static ClassLoader getLowestClassLoader(Class[] classes) {
146: ClassLoader loader = classes[0].getClassLoader();
147: for (int i = 1; i < classes.length; i++) {
148: Class other = classes[i];
149: if (SystemDefinitionContainer.isChildOf(other
150: .getClassLoader(), loader)) {
151: loader = other.getClassLoader();
152: } else if (SystemDefinitionContainer.isChildOf(loader,
153: other.getClassLoader())) {
154: // loader is fine
155: } else {
156: throw new RuntimeException(
157: "parallel classloader hierarchy not supported");
158: }
159: }
160: return loader;
161: }
162:
163: /**
164: * A composite key for the proxy cache.
165: */
166: private static class CompositeClassKey {
167: private final Class[] m_interfaces;
168:
169: CompositeClassKey(Class[] interfaces) {
170: m_interfaces = interfaces;
171: }
172:
173: public boolean equals(Object o) {
174: if (this == o)
175: return true;
176: if (!(o instanceof CompositeClassKey))
177: return false;
178:
179: final CompositeClassKey compositeClassKey = (CompositeClassKey) o;
180:
181: if (!Arrays.equals(m_interfaces,
182: compositeClassKey.m_interfaces))
183: return false;
184:
185: return true;
186: }
187:
188: public int hashCode() {
189: int result = 1;
190: for (int i = 0; i < m_interfaces.length; i++) {
191: result = 31 * result + m_interfaces[i].hashCode();
192: }
193: return result;
194: }
195: }
196:
197: }
|