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.exception.WrappedRuntimeException;
008:
009: import java.util.Map;
010: import java.util.WeakHashMap;
011:
012: /**
013: * Get proxy classes from target classes and weaves in all matching aspects deployed in the class loader
014: * and defined by the <code>META-INF/aop.xml</code> file.
015: *
016: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
017: */
018: public class ProxySubclassingStrategy {
019:
020: /**
021: * The suffix for the compiled proxy classes.
022: */
023: public static final String PROXY_SUFFIX = "$$ProxiedByAWSubclassing$$";
024:
025: /**
026: * Cache for the compiled proxy classes. Target class is key.
027: */
028: private static final Map PROXY_CLASS_CACHE = new WeakHashMap();
029:
030: /**
031: * Creates a new proxy instance based for the class specified and instantiates it using its default no-argument
032: * constructor. <p/> The proxy will be cached and non-advisable.
033: *
034: * @param clazz the target class to make a proxy for
035: * @return the proxy instance
036: */
037: static Object newInstance(final Class clazz,
038: final SystemDefinition definition) {
039: try {
040: Class proxyClass = getProxyClassFor(clazz, true, false,
041: definition);
042: return proxyClass.newInstance();
043: } catch (Throwable t) {
044: throw new WrappedRuntimeException(t);
045: }
046: }
047:
048: /**
049: * Creates a new proxy instance for the class specified and instantiates it using the constructor matching
050: * the argument type array specified.
051: * <p/>
052: * The proxy will be cached and non-advisable.
053: *
054: * @param clazz the target class to make a proxy for
055: * @param argumentTypes the argument types matching the signature of the constructor to use when instantiating the proxy
056: * @param argumentValues the argument values to use when instantiating the proxy
057: * @return the proxy instance
058: */
059: static Object newInstance(final Class clazz,
060: final Class[] argumentTypes, final Object[] argumentValues,
061: final SystemDefinition definition) {
062: try {
063: Class proxyClass = getProxyClassFor(clazz, true, false,
064: definition);
065: return proxyClass.getDeclaredConstructor(argumentTypes)
066: .newInstance(argumentValues);
067: } catch (Throwable t) {
068: throw new WrappedRuntimeException(t);
069: }
070: }
071:
072: /**
073: * Creates a new proxy instance based for the class specified and instantiates it using its default no-argument
074: * constructor.
075: *
076: * @param clazz the target class to make a proxy for
077: * @param useCache true if a cached instance of the proxy classed should be used
078: * @param makeAdvisable true if the proxy class should implement the <code>Advisable</code> interface,
079: * e.g. be prepared for programmatic, runtime, per instance hot deployement of advice
080: * @return the proxy instance
081: */
082: static Object newInstance(final Class clazz,
083: final boolean useCache, final boolean makeAdvisable,
084: final SystemDefinition definition) {
085: try {
086: Class proxyClass = getProxyClassFor(clazz, useCache,
087: makeAdvisable, definition);
088: return proxyClass.newInstance();
089: } catch (Throwable t) {
090: throw new WrappedRuntimeException(t);
091: }
092: }
093:
094: /**
095: * Creates a new proxy instance for the class specified and instantiates it using the constructor matching
096: * the argument type array specified.
097: *
098: * @param clazz the target class to make a proxy for
099: * @param argumentTypes the argument types matching the signature of the constructor to use when instantiating the proxy
100: * @param argumentValues the argument values to use when instantiating the proxy
101: * @param useCache true if a cached instance of the proxy classed should be used
102: * @param makeAdvisable true if the proxy class should implement the <code>Advisable</code> interface,
103: * e.g. be prepared for programmatic, runtime, per instance hot deployement of advice
104: * @return the proxy instance
105: */
106: static Object newInstance(final Class clazz,
107: final Class[] argumentTypes, final Object[] argumentValues,
108: final boolean useCache, final boolean makeAdvisable,
109: final SystemDefinition definition) {
110: try {
111: Class proxyClass = getProxyClassFor(clazz, useCache,
112: makeAdvisable, definition);
113: return proxyClass.getDeclaredConstructor(argumentTypes)
114: .newInstance(argumentValues);
115: } catch (Throwable t) {
116: throw new WrappedRuntimeException(t);
117: }
118: }
119:
120: /**
121: * Compiles and returns a proxy class for the class specified.
122: *
123: * @param clazz the target class to make a proxy for
124: * @param useCache true if a cached instance of the proxy classed should be used
125: * @param makeAdvisable true if the proxy class should implement the <code>Advisable</code> interface,
126: * e.g. be prepared for programmatic, runtime, per instance hot deployement of advice
127: * @return the proxy class
128: */
129: static Class getProxyClassFor(final Class clazz,
130: final boolean useCache, final boolean makeAdvisable,
131: final SystemDefinition definition) {
132:
133: // TODO - add support for proxying java.* classes
134: if (clazz.getName().startsWith("java.")) {
135: throw new RuntimeException(
136: "can not create proxies from system classes (java.*)");
137: }
138: final Class proxyClass;
139: if (!useCache) {
140: proxyClass = getNewProxyClassFor(clazz, makeAdvisable,
141: definition);
142: } else {
143: synchronized (PROXY_CLASS_CACHE) {
144: Object cachedProxyClass = PROXY_CLASS_CACHE.get(clazz);
145: if (cachedProxyClass != null) {
146: return (Class) cachedProxyClass;
147: }
148: proxyClass = getNewProxyClassFor(clazz, makeAdvisable,
149: definition);
150: PROXY_CLASS_CACHE.put(clazz, proxyClass);
151: }
152: }
153: ProxyCompilerHelper.compileJoinPoint(proxyClass, definition);
154: return proxyClass;
155: }
156:
157: /**
158: * Compiles and returns a proxy class for the class specified.
159: * No cache is used, but compiles a new one each invocation.
160: *
161: * @param clazz
162: * @param makeAdvisable true if the proxy class should implement the <code>Advisable</code> interface,
163: * e.g. be prepared for programmatic, runtime, per instance hot deployement of advice
164: * @return the proxy class
165: */
166: private static Class getNewProxyClassFor(final Class clazz,
167: final boolean makeAdvisable,
168: final SystemDefinition definition) {
169: ClassLoader loader = clazz.getClassLoader();
170: String proxyClassName = definition.getUuid();
171: if (makeAdvisable) {
172: Proxy
173: .makeProxyAdvisable(proxyClassName, loader,
174: definition);
175: }
176: final byte[] bytes = ProxySubclassingCompiler.compileProxyFor(
177: clazz, proxyClassName);
178: return ProxyCompilerHelper.weaveAndDefineProxyClass(bytes,
179: loader, proxyClassName.replace('/', '.'), definition);
180: }
181:
182: /**
183: * Returns a unique name for the proxy class.
184: *
185: * @param proxyClassName
186: * @return the class name beeing proxied
187: */
188: static String getUniqueClassNameFromProxy(
189: final String proxyClassName) {
190: int index = proxyClassName.lastIndexOf(PROXY_SUFFIX);
191: if (index > 0) {
192: return proxyClassName.substring(0, index);
193: } else {
194: return null;
195: }
196: }
197: }
|