KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > proxy > compiler > ProxyCompiler


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.proxy.compiler;
23
24 import java.lang.reflect.Method JavaDoc;
25
26 import org.apache.bcel.Constants;
27 import org.apache.bcel.classfile.JavaClass;
28 import org.apache.bcel.generic.ClassGen;
29 import org.apache.bcel.generic.BasicType;
30 import org.apache.bcel.generic.Type;
31
32 import org.jboss.logging.Logger;
33
34 /**
35  * Manages bytecode assembly for dynamic proxy generation.
36  *
37  * @version <tt>$Revision: 37459 $</tt>
38  * @author Unknown
39  * @author <a HREF="mailto:jason@planet57.com">Jason Dillon</a>
40  */

41 public class ProxyCompiler
42 {
43    /** Class logger. */
44    private static final Logger log = Logger.getLogger(ProxyCompiler.class);
45
46    /** The path (if non-null) where generated classes will be dumped for debugging. */
47    public final static String JavaDoc CLASS_DUMP_PATH =
48       System.getProperty(ProxyCompiler.class.getName() + ".dumpPath", null);
49
50    /** The suffix for proxy implementation classnames. */
51    public final static String JavaDoc IMPL_SUFFIX = "$Proxy";
52
53    /** The Runtime classloader for the target proxy. */
54    Runtime JavaDoc runtime;
55
56    /** The superclass of the target proxy. */
57    Class JavaDoc superclass;
58
59    /** The implementing types of the target proxy. */
60    Class JavaDoc targetTypes[];
61
62    /** The implementing methods of the target proxy. */
63    Method JavaDoc methods[];
64
65    /** The class of the targret proxy (set by runtime). */
66    Class JavaDoc proxyType;
67    
68    /**
69     * Creates a new <code>ProxyCompiler</code> instance.
70     *
71     * @param parent a <code>ClassLoader</code> value
72     * @param superclass a <code>Class</code> value
73     * @param targetTypes a <code>Class</code> value
74     * @param methods a <code>Method</code> value
75     */

76    public ProxyCompiler(final ClassLoader JavaDoc parent,
77                         final Class JavaDoc superclass,
78                         final Class JavaDoc targetTypes[],
79                         final Method JavaDoc methods[])
80       throws Exception JavaDoc
81    {
82       this.superclass = superclass;
83       this.targetTypes = targetTypes;
84       this.methods = methods;
85
86       this.runtime = new Runtime JavaDoc(parent);
87       this.runtime.targetTypes = targetTypes;
88       this.runtime.methods = methods;
89
90       runtime.makeProxyType(this);
91    }
92
93    public Class JavaDoc getProxyType() {
94       return proxyType;
95    }
96    
97    public String JavaDoc getProxyClassName() {
98       // Note: We could reasonably put the $Impl class in either
99
// of two packges: The package of Proxies, or the same package
100
// as the target type. We choose to put it in same package as
101
// the target type, to avoid name encoding issues.
102
//
103
// Note that all infrastructure must be public, because the
104
// $Impl class is inside a different class loader.
105

106       return targetTypes[0].getName() + IMPL_SUFFIX;
107    }
108       
109    /**
110     * Create the implementation class for the given target.
111     *
112     * @return a <code>byte[]</code> value
113     */

114    public byte[] getCode()
115    {
116       boolean trace = log.isTraceEnabled();
117
118       final String JavaDoc proxyClassName = getProxyClassName();
119       final String JavaDoc superClassName = superclass.getName();
120
121       int icount = 1; // don't forget ProxyTarget
122
for (int i = 0; i < targetTypes.length; i++) {
123          Class JavaDoc targetType = targetTypes[i];
124          if (targetType.isInterface()) {
125             icount++;
126          }
127       }
128
129       String JavaDoc interfaceNames[] = new String JavaDoc[icount];
130       interfaceNames[0] = Proxies.ProxyTarget.class.getName();
131       icount = 1;
132       for (int i = 0; i < targetTypes.length; i++) {
133          Class JavaDoc targetType = targetTypes[i];
134          if (targetType.isInterface()) {
135             interfaceNames[icount++] = targetType.getName();
136          }
137          else if (!superclass.isAssignableFrom(targetType)) {
138             throw new RuntimeException JavaDoc("unexpected: " + targetType);
139          }
140       }
141
142       ClassGen cg = new ClassGen(proxyClassName,
143                                  superClassName,
144                                  "<generated>",
145                                  Constants.ACC_PUBLIC | Constants.ACC_FINAL,
146                  interfaceNames);
147       
148       ProxyImplementationFactory factory =
149          new ProxyImplementationFactory(superClassName, proxyClassName, cg);
150
151       cg.addField(factory.createInvocationHandlerField());
152       cg.addField(factory.createRuntimeField());
153       cg.addMethod(factory.createConstructor());
154       
155       // ProxyTarget implementation
156

157       cg.addMethod(factory.createGetInvocationHandler());
158       cg.addMethod(factory.createGetTargetTypes());
159            
160       boolean haveToString = false;
161
162       if (trace) log.trace("Creating proxy methods...");
163
164       // Implement the methods of the target types.
165
for (int i = 0; i < methods.length; i++)
166       {
167          Method JavaDoc m = methods[i];
168          if (trace) log.trace("Reflected method: " + m);
169
170          String JavaDoc name = m.getName();
171          Class JavaDoc rTypeClass = m.getReturnType();
172          String JavaDoc rTypeName = rTypeClass.getName();
173          Type rType = Utility.getType(rTypeClass);
174          Type[] pTypes = Utility.getTypes(m.getParameterTypes());
175          String JavaDoc[] exceptionNames = getNames(m.getExceptionTypes());
176
177          if (name.equals("toString") && pTypes.length == 0) {
178             haveToString = true;
179          }
180
181          org.apache.bcel.classfile.Method proxyMethod =
182             factory.createProxyMethod(name, i, rType, pTypes, exceptionNames);
183
184          if (trace) log.trace("Created proxy method: " + proxyMethod);
185
186          cg.addMethod(proxyMethod);
187       }
188
189       if (!haveToString) {
190          cg.addMethod(factory.createToString());
191       }
192
193       JavaClass jclass = cg.getJavaClass();
194       if (trace) log.trace("Generated Java class: " + jclass);
195
196       // dump the class if we have been configured todo so
197
if (CLASS_DUMP_PATH != null) {
198          try {
199             String JavaDoc filename = CLASS_DUMP_PATH + java.io.File.separator + proxyClassName + ".class";
200             log.info("Dumping generated proxy class to " + filename);
201             jclass.dump(filename);
202          }
203          catch (Exception JavaDoc e) {
204             log.error("Failed to dump class file", e);
205          }
206       }
207
208       return jclass.getBytes();
209    }
210    
211    /**
212     * Returns an array of class names for the given array
213     * of classes.
214     */

215    private String JavaDoc[] getNames(Class JavaDoc[] classes) {
216       String JavaDoc[] names = new String JavaDoc[classes.length];
217       for ( int i = 0; i < classes.length; i++ ) {
218          names[i] = classes[i].getName();
219       }
220
221       return names;
222    }
223 }
224
Popular Tags