001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist.tools.rmi;
017:
018: import javassist.*;
019: import java.lang.reflect.Method;
020: import java.util.Hashtable;
021: import javassist.CtMethod.ConstParameter;
022:
023: /**
024: * A stub-code generator. It is used for producing a proxy class.
025: *
026: * <p>The proxy class for class A is as follows:
027: *
028: * <ul><pre>public class A implements Proxy, Serializable {
029: * private ObjectImporter importer;
030: * private int objectId;
031: * public int _getObjectId() { return objectId; }
032: * public A(ObjectImporter oi, int id) {
033: * importer = oi; objectId = id;
034: * }
035: *
036: * ... the same methods that the original class A declares ...
037: * }</pre></ul>
038: *
039: * <p>Instances of the proxy class is created by an
040: * <code>ObjectImporter</code> object.
041: */
042: public class StubGenerator implements Translator {
043: private static final String fieldImporter = "importer";
044: private static final String fieldObjectId = "objectId";
045: private static final String accessorObjectId = "_getObjectId";
046: private static final String sampleClass = "javassist.tools.rmi.Sample";
047:
048: private ClassPool classPool;
049: private Hashtable proxyClasses;
050: private CtMethod forwardMethod;
051: private CtMethod forwardStaticMethod;
052:
053: private CtClass[] proxyConstructorParamTypes;
054: private CtClass[] interfacesForProxy;
055: private CtClass[] exceptionForProxy;
056:
057: /**
058: * Constructs a stub-code generator.
059: */
060: public StubGenerator() {
061: proxyClasses = new Hashtable();
062: }
063:
064: /**
065: * Initializes the object.
066: * This is a method declared in javassist.Translator.
067: *
068: * @see javassist.Translator#start(ClassPool)
069: */
070: public void start(ClassPool pool) throws NotFoundException {
071: classPool = pool;
072: CtClass c = pool.get(sampleClass);
073: forwardMethod = c.getDeclaredMethod("forward");
074: forwardStaticMethod = c.getDeclaredMethod("forwardStatic");
075:
076: proxyConstructorParamTypes = pool.get(new String[] {
077: "javassist.tools.rmi.ObjectImporter", "int" });
078: interfacesForProxy = pool.get(new String[] {
079: "java.io.Serializable", "javassist.tools.rmi.Proxy" });
080: exceptionForProxy = new CtClass[] { pool
081: .get("javassist.tools.rmi.RemoteException") };
082: }
083:
084: /**
085: * Does nothing.
086: * This is a method declared in javassist.Translator.
087: * @see javassist.Translator#onLoad(ClassPool,String)
088: */
089: public void onLoad(ClassPool pool, String classname) {
090: }
091:
092: /**
093: * Returns <code>true</code> if the specified class is a proxy class
094: * recorded by <code>makeProxyClass()</code>.
095: *
096: * @param name a fully-qualified class name
097: */
098: public boolean isProxyClass(String name) {
099: return proxyClasses.get(name) != null;
100: }
101:
102: /**
103: * Makes a proxy class. The produced class is substituted
104: * for the original class.
105: *
106: * @param clazz the class referenced
107: * through the proxy class.
108: * @return <code>false</code> if the proxy class
109: * has been already produced.
110: */
111: public synchronized boolean makeProxyClass(Class clazz)
112: throws CannotCompileException, NotFoundException {
113: String classname = clazz.getName();
114: if (proxyClasses.get(classname) != null)
115: return false;
116: else {
117: CtClass ctclazz = produceProxyClass(classPool
118: .get(classname), clazz);
119: proxyClasses.put(classname, ctclazz);
120: modifySuperclass(ctclazz);
121: return true;
122: }
123: }
124:
125: private CtClass produceProxyClass(CtClass orgclass, Class orgRtClass)
126: throws CannotCompileException, NotFoundException {
127: int modify = orgclass.getModifiers();
128: if (Modifier.isAbstract(modify) || Modifier.isNative(modify)
129: || !Modifier.isPublic(modify))
130: throw new CannotCompileException(orgclass.getName()
131: + " must be public, non-native, and non-abstract.");
132:
133: CtClass proxy = classPool.makeClass(orgclass.getName(),
134: orgclass.getSuperclass());
135:
136: proxy.setInterfaces(interfacesForProxy);
137:
138: CtField f = new CtField(classPool
139: .get("javassist.tools.rmi.ObjectImporter"),
140: fieldImporter, proxy);
141: f.setModifiers(Modifier.PRIVATE);
142: proxy.addField(f, CtField.Initializer.byParameter(0));
143:
144: f = new CtField(CtClass.intType, fieldObjectId, proxy);
145: f.setModifiers(Modifier.PRIVATE);
146: proxy.addField(f, CtField.Initializer.byParameter(1));
147:
148: proxy.addMethod(CtNewMethod.getter(accessorObjectId, f));
149:
150: proxy
151: .addConstructor(CtNewConstructor
152: .defaultConstructor(proxy));
153: CtConstructor cons = CtNewConstructor.skeleton(
154: proxyConstructorParamTypes, null, proxy);
155: proxy.addConstructor(cons);
156:
157: try {
158: addMethods(proxy, orgRtClass.getMethods());
159: return proxy;
160: } catch (SecurityException e) {
161: throw new CannotCompileException(e);
162: }
163: }
164:
165: private CtClass toCtClass(Class rtclass) throws NotFoundException {
166: String name;
167: if (!rtclass.isArray())
168: name = rtclass.getName();
169: else {
170: StringBuffer sbuf = new StringBuffer();
171: do {
172: sbuf.append("[]");
173: rtclass = rtclass.getComponentType();
174: } while (rtclass.isArray());
175: sbuf.insert(0, rtclass.getName());
176: name = sbuf.toString();
177: }
178:
179: return classPool.get(name);
180: }
181:
182: private CtClass[] toCtClass(Class[] rtclasses)
183: throws NotFoundException {
184: int n = rtclasses.length;
185: CtClass[] ctclasses = new CtClass[n];
186: for (int i = 0; i < n; ++i)
187: ctclasses[i] = toCtClass(rtclasses[i]);
188:
189: return ctclasses;
190: }
191:
192: /* ms must not be an array of CtMethod. To invoke a method ms[i]
193: * on a server, a client must send i to the server.
194: */
195: private void addMethods(CtClass proxy, Method[] ms)
196: throws CannotCompileException, NotFoundException {
197: CtMethod wmethod;
198: for (int i = 0; i < ms.length; ++i) {
199: Method m = ms[i];
200: int mod = m.getModifiers();
201: if (m.getDeclaringClass() != Object.class
202: && !Modifier.isFinal(mod))
203: if (Modifier.isPublic(mod)) {
204: CtMethod body;
205: if (Modifier.isStatic(mod))
206: body = forwardStaticMethod;
207: else
208: body = forwardMethod;
209:
210: wmethod = CtNewMethod.wrapped(toCtClass(m
211: .getReturnType()), m.getName(), toCtClass(m
212: .getParameterTypes()), exceptionForProxy,
213: body, ConstParameter.integer(i), proxy);
214: wmethod.setModifiers(mod);
215: proxy.addMethod(wmethod);
216: } else if (!Modifier.isProtected(mod)
217: && !Modifier.isPrivate(mod))
218: // if package method
219: throw new CannotCompileException(
220: "the methods must be public, protected, or private.");
221: }
222: }
223:
224: /**
225: * Adds a default constructor to the super classes.
226: */
227: private void modifySuperclass(CtClass orgclass)
228: throws CannotCompileException, NotFoundException {
229: CtClass super clazz;
230: for (;; orgclass = super clazz) {
231: super clazz = orgclass.getSuperclass();
232: if (super clazz == null)
233: break;
234:
235: try {
236: super clazz.getDeclaredConstructor(null);
237: break; // the constructor with no arguments is found.
238: } catch (NotFoundException e) {
239: }
240:
241: superclazz.addConstructor(CtNewConstructor
242: .defaultConstructor(superclazz));
243: }
244: }
245: }
|