aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/javassist/rmi/StubGenerator.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/javassist/rmi/StubGenerator.java')
-rw-r--r--src/main/javassist/rmi/StubGenerator.java261
1 files changed, 261 insertions, 0 deletions
diff --git a/src/main/javassist/rmi/StubGenerator.java b/src/main/javassist/rmi/StubGenerator.java
new file mode 100644
index 00000000..9e77c383
--- /dev/null
+++ b/src/main/javassist/rmi/StubGenerator.java
@@ -0,0 +1,261 @@
+/*
+ * This file is part of the Javassist toolkit.
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * either http://www.mozilla.org/MPL/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Original Code is Javassist.
+ *
+ * The Initial Developer of the Original Code is Shigeru Chiba. Portions
+ * created by Shigeru Chiba are Copyright (C) 1999-2003 Shigeru Chiba.
+ * All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * The development of this software is supported in part by the PRESTO
+ * program (Sakigake Kenkyu 21) of Japan Science and Technology Corporation.
+ */
+
+package javassist.rmi;
+
+import java.io.*;
+import javassist.*;
+import java.lang.reflect.Method;
+import java.util.Hashtable;
+import javassist.CtMethod.ConstParameter;
+
+/**
+ * A stub-code generator. It is used for producing a proxy class.
+ *
+ * <p>The proxy class for class A is as follows:
+ *
+ * <ul><pre>public class A implements Proxy, Serializable {
+ * private ObjectImporter importer;
+ * private int objectId;
+ * public int _getObjectId() { return objectId; }
+ * public A(ObjectImporter oi, int id) {
+ * importer = oi; objectId = id;
+ * }
+ *
+ * ... the same methods that the original class A declares ...
+ * }</pre></ul>
+ *
+ * <p>Instances of the proxy class is created by an
+ * <code>ObjectImporter</code> object.
+ */
+public class StubGenerator implements Translator {
+ private static final String fieldImporter = "importer";
+ private static final String fieldObjectId = "objectId";
+ private static final String accessorObjectId = "_getObjectId";
+ private static final String sampleClass = "javassist.rmi.Sample";
+
+ private ClassPool classPool;
+ private Hashtable proxyClasses;
+ private CtMethod forwardMethod;
+ private CtMethod forwardStaticMethod;
+
+ private CtClass[] proxyConstructorParamTypes;
+ private CtClass[] interfacesForProxy;
+ private CtClass[] exceptionForProxy;
+
+ /**
+ * Constructs a stub-code generator.
+ */
+ public StubGenerator() {
+ proxyClasses = new Hashtable();
+ }
+
+ /**
+ * Is a method declared in javassist.Translator.
+ *
+ * @see javassist.Translator#start(ClassPool)
+ */
+ public void start(ClassPool pool) throws NotFoundException {
+ classPool = pool;
+ CtClass c = pool.get(sampleClass);
+ forwardMethod = c.getDeclaredMethod("forward");
+ forwardStaticMethod = c.getDeclaredMethod("forwardStatic");
+
+ proxyConstructorParamTypes
+ = pool.get(new String[] { "javassist.rmi.ObjectImporter",
+ "int" });
+ interfacesForProxy
+ = pool.get(new String[] { "java.io.Serializable",
+ "javassist.rmi.Proxy" });
+ exceptionForProxy
+ = new CtClass[] { pool.get("javassist.rmi.RemoteException") };
+ }
+
+ public void onWrite(ClassPool pool, String classname) {}
+
+ /**
+ * Returns <code>true</code> if the specified class is a proxy class
+ * recorded by <code>makeProxyClass()</code>.
+ *
+ * @param name a fully-qualified class name
+ */
+ public boolean isProxyClass(String name) {
+ return proxyClasses.get(name) != null;
+ }
+
+ /**
+ * Makes a proxy class. The produced class is substituted
+ * for the original class.
+ *
+ * @param clazz the class referenced
+ * through the proxy class.
+ * @return <code>false</code> if the proxy class
+ * has been already produced.
+ */
+ public synchronized boolean makeProxyClass(Class clazz)
+ throws CannotCompileException, NotFoundException
+ {
+ String classname = clazz.getName();
+ if (proxyClasses.get(classname) != null)
+ return false;
+ else {
+ CtClass ctclazz = produceProxyClass(classPool.get(classname),
+ clazz);
+ proxyClasses.put(classname, ctclazz);
+ modifySuperclass(ctclazz);
+ return true;
+ }
+ }
+
+ private CtClass produceProxyClass(CtClass orgclass, Class orgRtClass)
+ throws CannotCompileException, NotFoundException
+ {
+ int modify = orgclass.getModifiers();
+ if (Modifier.isAbstract(modify) || Modifier.isNative(modify)
+ || !Modifier.isPublic(modify))
+ throw new CannotCompileException(orgclass.getName()
+ + " must be public, non-native, and non-abstract.");
+
+ CtClass proxy = classPool.makeClass(orgclass.getName(),
+ orgclass.getSuperclass());
+
+ proxy.setInterfaces(interfacesForProxy);
+
+ CtField f
+ = new CtField(classPool.get("javassist.rmi.ObjectImporter"),
+ fieldImporter, proxy);
+ f.setModifiers(Modifier.PRIVATE);
+ proxy.addField(f, CtField.Initializer.byParameter(0));
+
+ f = new CtField(CtClass.intType, fieldObjectId, proxy);
+ f.setModifiers(Modifier.PRIVATE);
+ proxy.addField(f, CtField.Initializer.byParameter(1));
+
+ proxy.addMethod(CtNewMethod.getter(accessorObjectId, f));
+
+ proxy.addConstructor(CtNewConstructor.defaultConstructor(proxy));
+ CtConstructor cons
+ = CtNewConstructor.skeleton(proxyConstructorParamTypes,
+ null, proxy);
+ proxy.addConstructor(cons);
+
+ try {
+ addMethods(proxy, orgRtClass.getMethods());
+ return proxy;
+ }
+ catch (SecurityException e) {
+ throw new CannotCompileException(e);
+ }
+ }
+
+ private CtClass toCtClass(Class rtclass) throws NotFoundException {
+ String name;
+ if (!rtclass.isArray())
+ name = rtclass.getName();
+ else {
+ StringBuffer sbuf = new StringBuffer();
+ do {
+ sbuf.append("[]");
+ rtclass = rtclass.getComponentType();
+ } while(rtclass.isArray());
+ sbuf.insert(0, rtclass.getName());
+ name = sbuf.toString();
+ }
+
+ return classPool.get(name);
+ }
+
+ private CtClass[] toCtClass(Class[] rtclasses) throws NotFoundException {
+ int n = rtclasses.length;
+ CtClass[] ctclasses = new CtClass[n];
+ for (int i = 0; i < n; ++i)
+ ctclasses[i] = toCtClass(rtclasses[i]);
+
+ return ctclasses;
+ }
+
+ /* ms must not be an array of CtMethod. To invoke a method ms[i]
+ * on a server, a client must send i to the server.
+ */
+ private void addMethods(CtClass proxy, Method[] ms)
+ throws CannotCompileException, NotFoundException
+ {
+ CtMethod wmethod;
+ for (int i = 0; i < ms.length; ++i) {
+ Method m = ms[i];
+ int mod = m.getModifiers();
+ if (m.getDeclaringClass() != Object.class
+ && !Modifier.isFinal(mod))
+ if (Modifier.isPublic(mod)) {
+ CtMethod body;
+ if (Modifier.isStatic(mod))
+ body = forwardStaticMethod;
+ else
+ body = forwardMethod;
+
+ wmethod
+ = CtNewMethod.wrapped(toCtClass(m.getReturnType()),
+ m.getName(),
+ toCtClass(m.getParameterTypes()),
+ exceptionForProxy,
+ body,
+ ConstParameter.integer(i),
+ proxy);
+ wmethod.setModifiers(mod);
+ proxy.addMethod(wmethod);
+ }
+ else if (!Modifier.isProtected(mod)
+ && !Modifier.isPrivate(mod))
+ // if package method
+ throw new CannotCompileException(
+ "the methods must be public, protected, or private.");
+ }
+ }
+
+ /**
+ * Adds a default constructor to the super classes.
+ */
+ private void modifySuperclass(CtClass orgclass)
+ throws CannotCompileException, NotFoundException
+ {
+ CtClass superclazz;
+ for (;; orgclass = superclazz) {
+ superclazz = orgclass.getSuperclass();
+ if (superclazz == null)
+ break;
+
+ String name = superclazz.getName();
+ try {
+ superclazz.getDeclaredConstructor(null);
+ break; // the constructor with no arguments is found.
+ }
+ catch (NotFoundException e) {
+ }
+
+ superclazz.addConstructor(
+ CtNewConstructor.defaultConstructor(superclazz));
+ }
+ }
+}