KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > aspectwerkz > proxy > Proxy


1 /**************************************************************************************
2  * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved. *
3  * http://aspectwerkz.codehaus.org *
4  * ---------------------------------------------------------------------------------- *
5  * The software in this package is published under the terms of the LGPL license *
6  * a copy of which has been included with this distribution in the license.txt file. *
7  **************************************************************************************/

8 package org.codehaus.aspectwerkz.proxy;
9
10 import java.util.WeakHashMap JavaDoc;
11 import java.util.Map JavaDoc;
12 import java.util.Set JavaDoc;
13 import java.util.Iterator JavaDoc;
14
15 import org.codehaus.aspectwerkz.hook.impl.ClassPreProcessorHelper;
16 import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
17 import org.codehaus.aspectwerkz.definition.DefinitionParserHelper;
18 import org.codehaus.aspectwerkz.definition.SystemDefinition;
19 import org.codehaus.aspectwerkz.definition.SystemDefinitionContainer;
20 import org.codehaus.aspectwerkz.intercept.AdvisableImpl;
21 import org.codehaus.aspectwerkz.DeploymentModel;
22
23 /**
24  * Compiles proxy classes from target classes and weaves in all matching aspects deployed in the class loader
25  * and defined by the <code>META-INF/aop.xml</code> file.
26  *
27  * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
28  */

29 public class Proxy {
30
31     /**
32      * The suffix for the compiled proxy classes.
33      */

34     public static final String JavaDoc PROXY_SUFFIX_START = "$$ProxiedByAW$$";
35
36     /**
37      * Cache for the compiled proxy classes. Target class is key.
38      */

39     private static final Map JavaDoc PROXY_CLASS_CACHE = new WeakHashMap JavaDoc();
40
41     /**
42      * Creates a new proxy instance based for the class specified and instantiates it using its default no-argument
43      * constructor.
44      * <p/>
45      * The proxy will be cached and non-advisable.
46      *
47      * @param clazz the target class to make a proxy for
48      * @return the proxy instance
49      */

50     public static Object JavaDoc newInstance(final Class JavaDoc clazz) {
51         try {
52             Class JavaDoc proxyClass = getProxyClassFor(clazz, true, false);
53             return proxyClass.newInstance();
54         } catch (Throwable JavaDoc e) {
55             e.printStackTrace();
56             throw new Error JavaDoc(e.toString());
57         }
58     }
59
60     /**
61      * Creates a new proxy instance for the class specified and instantiates it using the constructor matching
62      * the argument type array specified.
63      * <p/>
64      * The proxy will be cached and non-advisable.
65      *
66      * @param clazz the target class to make a proxy for
67      * @param argumentTypes the argument types matching the signature of the constructor to use when instantiating the proxy
68      * @param argumentValues the argument values to use when instantiating the proxy
69      * @return the proxy instance
70      */

71     public static Object JavaDoc newInstance(final Class JavaDoc clazz, final Class JavaDoc[] argumentTypes, final Object JavaDoc[] argumentValues) {
72         try {
73             Class JavaDoc proxyClass = getProxyClassFor(clazz, true, false);
74             return proxyClass.getDeclaredConstructor(argumentTypes).newInstance(argumentValues);
75         } catch (Throwable JavaDoc e) {
76             e.printStackTrace();
77             throw new Error JavaDoc(e.toString());
78         }
79     }
80
81     /**
82      * Creates a new proxy instance based for the class specified and instantiates it using its default no-argument
83      * constructor.
84      *
85      * @param clazz the target class to make a proxy for
86      * @param useCache true if a cached instance of the proxy classed should be used
87      * @param makeAdvisable true if the proxy class should implement the <code>Advisable</code> interface,
88      * e.g. be prepared for programmatic, runtime, per instance hot deployement of advice
89      * @return the proxy instance
90      */

91     public static Object JavaDoc newInstance(final Class JavaDoc clazz, final boolean useCache, final boolean makeAdvisable) {
92         try {
93             Class JavaDoc proxyClass = getProxyClassFor(clazz, useCache, makeAdvisable);
94             return proxyClass.newInstance();
95         } catch (Throwable JavaDoc e) {
96             e.printStackTrace();
97             throw new Error JavaDoc(e.toString());
98         }
99     }
100
101     /**
102      * Creates a new proxy instance for the class specified and instantiates it using the constructor matching
103      * the argument type array specified.
104      *
105      * @param clazz the target class to make a proxy for
106      * @param argumentTypes the argument types matching the signature of the constructor to use when instantiating the proxy
107      * @param argumentValues the argument values to use when instantiating the proxy
108      * @param useCache true if a cached instance of the proxy classed should be used
109      * @param makeAdvisable true if the proxy class should implement the <code>Advisable</code> interface,
110      * e.g. be prepared for programmatic, runtime, per instance hot deployement of advice
111      * @return the proxy instance
112      */

113     public static Object JavaDoc newInstance(final Class JavaDoc clazz,
114                                      final Class JavaDoc[] argumentTypes,
115                                      final Object JavaDoc[] argumentValues,
116                                      final boolean useCache,
117                                      final boolean makeAdvisable) {
118         try {
119             Class JavaDoc proxyClass = getProxyClassFor(clazz, useCache, makeAdvisable);
120             return proxyClass.getDeclaredConstructor(argumentTypes).newInstance(argumentValues);
121         } catch (Throwable JavaDoc e) {
122             e.printStackTrace();
123             throw new Error JavaDoc(e.toString());
124         }
125     }
126
127     /**
128      * Compiles and returns a proxy class for the class specified.
129      *
130      * @param clazz the target class to make a proxy for
131      * @param useCache true if a cached instance of the proxy classed should be used
132      * @param makeAdvisable true if the proxy class should implement the <code>Advisable</code> interface,
133      * e.g. be prepared for programmatic, runtime, per instance hot deployement of advice
134      * @return the proxy class
135      */

136     public static Class JavaDoc getProxyClassFor(final Class JavaDoc clazz, final boolean useCache, final boolean makeAdvisable) {
137
138         // FIXME - add support for proxying java.* classes
139
if (clazz.getName().startsWith("java.")) {
140             throw new RuntimeException JavaDoc("can not create proxies from system classes (java.*)");
141         }
142         if (!useCache) {
143             return getNewProxyClassFor(clazz, makeAdvisable);
144         } else {
145             synchronized (PROXY_CLASS_CACHE) {
146                 Object JavaDoc cachedProxyClass = PROXY_CLASS_CACHE.get(clazz);
147                 if (cachedProxyClass != null) {
148                     return (Class JavaDoc) cachedProxyClass;
149                 }
150                 Class JavaDoc proxyClass = getNewProxyClassFor(clazz, makeAdvisable);
151                 PROXY_CLASS_CACHE.put(clazz, proxyClass);
152                 return proxyClass;
153             }
154         }
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 JavaDoc getNewProxyClassFor(final Class JavaDoc clazz, final boolean makeAdvisable) {
167         ClassLoader JavaDoc loader = clazz.getClassLoader();
168         String JavaDoc proxyClassName = getUniqueClassNameForProxy(clazz);
169
170         if (makeAdvisable) {
171             makeProxyAdvisable(clazz);
172         }
173
174         byte[] bytes = ProxyCompiler.compileProxyFor(clazz, proxyClassName);
175         byte[] transformedBytes = ClassPreProcessorHelper.defineClass0Pre(
176                 loader, proxyClassName, bytes, 0, bytes.length, null
177         );
178
179         return AsmHelper.defineClass(loader, transformedBytes, proxyClassName);
180     }
181
182     /**
183      * Returns a unique name for the proxy class.
184      *
185      * @param clazz target class
186      * @return the proxy class name
187      */

188     private static String JavaDoc getUniqueClassNameForProxy(final Class JavaDoc clazz) {
189         return clazz.getName().replace('.', '/') + PROXY_SUFFIX_START + new Long JavaDoc(Uuid.newUuid()).toString();
190     }
191
192     /**
193      * Returns a unique name for the proxy class.
194      *
195      * @param proxyClassName
196      * @return the class name beeing proxied
197      */

198     public static String JavaDoc getUniqueClassNameFromProxy(final String JavaDoc proxyClassName) {
199         int index = proxyClassName.lastIndexOf(PROXY_SUFFIX_START);
200         if (index > 0) {
201             return proxyClassName.substring(0, index);
202         } else {
203             return null;
204         }
205     }
206
207     /**
208      * Enhances the proxy class with the Advisable mixin, to allow runtime per instance additions of
209      * interceptors.
210      *
211      * @param clazz
212      */

213     private static void makeProxyAdvisable(final Class JavaDoc clazz) {
214         // changes occurs in the virtual definition only
215
SystemDefinition definition = SystemDefinitionContainer.getVirtualDefinitionAt(clazz.getClassLoader());
216         addAdvisableDefToSystemDef(clazz, definition);
217     }
218
219     private static void addAdvisableDefToSystemDef(final Class JavaDoc clazz, final SystemDefinition definition) {
220         String JavaDoc withinPointcut = "within(" + clazz.getName().replace('/', '.') + ')';
221         definition.addMixinDefinition(
222                 DefinitionParserHelper.createAndAddMixinDefToSystemDef(
223                         AdvisableImpl.CLASS_INFO,
224                         withinPointcut,
225                         DeploymentModel.PER_INSTANCE,
226                         false,
227                         definition
228                 )
229         );
230         DefinitionParserHelper.createAndAddAdvisableDef(
231                 "(execution(!static * *.*(..)) && " + withinPointcut + ')',
232                 definition
233         );
234     }
235 }
236
Popular Tags