aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/javassist/rmi
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/javassist/rmi')
-rw-r--r--src/main/javassist/rmi/AppletServer.java259
-rw-r--r--src/main/javassist/rmi/ObjectImporter.java308
-rw-r--r--src/main/javassist/rmi/ObjectNotFoundException.java36
-rw-r--r--src/main/javassist/rmi/Proxy.java35
-rw-r--r--src/main/javassist/rmi/RemoteException.java40
-rw-r--r--src/main/javassist/rmi/RemoteRef.java45
-rw-r--r--src/main/javassist/rmi/Sample.java46
-rw-r--r--src/main/javassist/rmi/StubGenerator.java261
8 files changed, 1030 insertions, 0 deletions
diff --git a/src/main/javassist/rmi/AppletServer.java b/src/main/javassist/rmi/AppletServer.java
new file mode 100644
index 00000000..2b8c30e5
--- /dev/null
+++ b/src/main/javassist/rmi/AppletServer.java
@@ -0,0 +1,259 @@
+/*
+ * 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.web.*;
+import javassist.CannotCompileException;
+import javassist.NotFoundException;
+import javassist.ClassPool;
+import java.lang.reflect.Method;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * An AppletServer object is a web server that an ObjectImporter
+ * communicates with. It makes the objects specified by
+ * <code>exportObject()</code> remotely accessible from applets.
+ * If the classes of the exported objects are requested by the client-side
+ * JVM, this web server sends proxy classes for the requested classes.
+ *
+ * @see javassist.rmi.ObjectImporter
+ */
+public class AppletServer extends Webserver {
+ private StubGenerator stubGen;
+ private Hashtable exportedNames;
+ private Vector exportedObjects;
+
+ private static final byte[] okHeader
+ = "HTTP/1.0 200 OK\r\n\r\n".getBytes();
+
+ /**
+ * Constructs a web server.
+ *
+ * @param port port number
+ */
+ public AppletServer(String port)
+ throws IOException, NotFoundException, CannotCompileException
+ {
+ this(Integer.parseInt(port));
+ }
+
+ /**
+ * Constructs a web server.
+ *
+ * @param port port number
+ */
+ public AppletServer(int port)
+ throws IOException, NotFoundException, CannotCompileException
+ {
+ this(ClassPool.getDefault(new StubGenerator()), port);
+ }
+
+ /**
+ * Constructs a web server.
+ *
+ * @param port port number
+ * @param src the source of classs files.
+ */
+ public AppletServer(int port, ClassPool src)
+ throws IOException, NotFoundException, CannotCompileException
+ {
+ this(new ClassPool(src, new StubGenerator()), port);
+ }
+
+ private AppletServer(ClassPool loader, int port)
+ throws IOException, NotFoundException, CannotCompileException
+ {
+ super(port);
+ exportedNames = new Hashtable();
+ exportedObjects = new Vector();
+ stubGen = (StubGenerator)loader.getTranslator();
+ setClassPool(loader);
+ }
+
+ /**
+ * Begins the HTTP service.
+ */
+ public void run() {
+ super.run();
+ }
+
+ /**
+ * Exports an object.
+ * This method produces the bytecode of the proxy class used
+ * to access the exported object. A remote applet can load
+ * the proxy class and call a method on the exported object.
+ *
+ * @param name the name used for looking the object up.
+ * @param object the exported object.
+ * @return the object identifier
+ *
+ * @see javassist.rmi.ObjectImporter#lookupObject(String)
+ */
+ public synchronized int exportObject(String name, Object obj)
+ throws CannotCompileException
+ {
+ Class clazz = obj.getClass();
+ ExportedObject eo = new ExportedObject();
+ eo.object = obj;
+ eo.methods = clazz.getMethods();
+ exportedObjects.addElement(eo);
+ eo.identifier = exportedObjects.size() - 1;
+ if (name != null)
+ exportedNames.put(name, eo);
+
+ try {
+ stubGen.makeProxyClass(clazz);
+ }
+ catch (NotFoundException e) {
+ throw new CannotCompileException(e);
+ }
+
+ return eo.identifier;
+ }
+
+ /**
+ * Processes a request from a web browser (an ObjectImporter).
+ */
+ public void doReply(InputStream in, OutputStream out, String cmd)
+ throws IOException, BadHttpRequest
+ {
+ if (cmd.startsWith("POST /rmi "))
+ processRMI(in, out);
+ else if (cmd.startsWith("POST /lookup "))
+ lookupName(cmd, in, out);
+ else
+ super.doReply(in, out, cmd);
+ }
+
+ private void processRMI(InputStream ins, OutputStream outs)
+ throws IOException
+ {
+ ObjectInputStream in = new ObjectInputStream(ins);
+
+ int objectId = in.readInt();
+ int methodId = in.readInt();
+ Exception err = null;
+ Object rvalue = null;
+ try {
+ ExportedObject eo
+ = (ExportedObject)exportedObjects.elementAt(objectId);
+ Object[] args = readParameters(in);
+ rvalue = convertRvalue(eo.methods[methodId].invoke(eo.object,
+ args));
+ }
+ catch(Exception e) {
+ err = e;
+ logging2(e.toString());
+ }
+
+ outs.write(okHeader);
+ ObjectOutputStream out = new ObjectOutputStream(outs);
+ if (err != null) {
+ out.writeBoolean(false);
+ out.writeUTF(err.toString());
+ }
+ else
+ try {
+ out.writeBoolean(true);
+ out.writeObject(rvalue);
+ }
+ catch (NotSerializableException e) {
+ logging2(e.toString());
+ }
+ catch (InvalidClassException e) {
+ logging2(e.toString());
+ }
+
+ out.flush();
+ out.close();
+ in.close();
+ }
+
+ private Object[] readParameters(ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ int n = in.readInt();
+ Object[] args = new Object[n];
+ for (int i = 0; i < n; ++i) {
+ Object a = in.readObject();
+ if (a instanceof RemoteRef) {
+ RemoteRef ref = (RemoteRef)a;
+ ExportedObject eo
+ = (ExportedObject)exportedObjects.elementAt(ref.oid);
+ a = eo.object;
+ }
+
+ args[i] = a;
+ }
+
+ return args;
+ }
+
+ private Object convertRvalue(Object rvalue)
+ throws CannotCompileException
+ {
+ if (rvalue == null)
+ return null; // the return type is void.
+
+ String classname = rvalue.getClass().getName();
+ if (stubGen.isProxyClass(classname))
+ return new RemoteRef(exportObject(null, rvalue), classname);
+ else
+ return rvalue;
+ }
+
+ private void lookupName(String cmd, InputStream ins, OutputStream outs)
+ throws IOException
+ {
+ ObjectInputStream in = new ObjectInputStream(ins);
+ String name = DataInputStream.readUTF(in);
+ ExportedObject found = (ExportedObject)exportedNames.get(name);
+ outs.write(okHeader);
+ ObjectOutputStream out = new ObjectOutputStream(outs);
+ if (found == null) {
+ logging2(name + "not found.");
+ out.writeInt(-1); // error code
+ out.writeUTF("error");
+ }
+ else {
+ logging2(name);
+ out.writeInt(found.identifier);
+ out.writeUTF(found.object.getClass().getName());
+ }
+
+ out.flush();
+ out.close();
+ in.close();
+ }
+}
+
+class ExportedObject {
+ public int identifier;
+ public Object object;
+ public Method[] methods;
+}
diff --git a/src/main/javassist/rmi/ObjectImporter.java b/src/main/javassist/rmi/ObjectImporter.java
new file mode 100644
index 00000000..19b6cb4e
--- /dev/null
+++ b/src/main/javassist/rmi/ObjectImporter.java
@@ -0,0 +1,308 @@
+/*
+ * 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 java.net.*;
+import java.awt.*;
+import java.applet.Applet;
+import java.lang.reflect.*;
+
+/**
+ * The object importer enables applets to call a method on a remote
+ * object running on the <code>Webserver</code>.
+ *
+ * <p>To access the remote
+ * object, the applet first calls <code>lookupObject()</code> and
+ * obtains a proxy object, which is a reference to that object.
+ * The class name of the proxy object is identical to that of
+ * the remote object.
+ * The proxy object provides the same set of methods as the remote object.
+ * If one of the methods is invoked on the proxy object,
+ * the invocation is delegated to the remote object.
+ * From the viewpoint of the applet, therefore, the two objects are
+ * identical. The applet can access the object on the server
+ * with the regular Java syntax without concern about the actual
+ * location.
+ *
+ * <p>The methods remotely called by the applet must be <code>public</code>.
+ * This is true even if the applet's class and the remote object's classs
+ * belong to the same package.
+ *
+ * <p>If class X is a class of remote objects, a subclass of X must be
+ * also a class of remote objects. On the other hand, this restriction
+ * is not applied to the superclass of X. The class X does not have to
+ * contain a constructor taking no arguments.
+ *
+ * <p>The parameters to a remote method is passed in the <i>call-by-value</i>
+ * manner. Thus all the parameter classes must implement
+ * <code>java.io.Serializable</code>. However, if the parameter is the
+ * proxy object, the reference to the remote object instead of a copy of
+ * the object is passed to the method.
+ *
+ * <p>Because of the limitations of the current implementation,
+ * <ul>
+ * <li>The parameter objects cannot contain the proxy
+ * object as a field value.
+ * <li>If class <code>C</code> is of the remote object, then
+ * the applet cannot instantiate <code>C</code> locally or remotely.
+ * </ul>
+ *
+ * <p>All the exceptions thrown by the remote object are converted
+ * into <code>RemoteException</code>. Since this exception is a subclass
+ * of <code>RuntimeException</code>, the caller method does not need
+ * to catch the exception. However, good programs should catch
+ * the <code>RuntimeException</code>.
+ *
+ * @see javassist.rmi.AppletServer
+ * @see javassist.rmi.RemoteException
+ * @see javassist.web.Viewer
+ */
+public class ObjectImporter implements java.io.Serializable {
+ private final byte[] endofline = { 0x0d, 0x0a };
+ private String servername, orgServername;
+ private int port, orgPort;
+
+ private byte[] lookupCommand = "POST /lookup HTTP/1.0".getBytes();
+ private byte[] rmiCommand = "POST /rmi HTTP/1.0".getBytes();
+
+ /**
+ * Constructs an object importer.
+ *
+ * <p>Remote objects are imported from the web server that the given
+ * applet has been loaded from.
+ *
+ * @param applet the applet loaded from the <code>Webserver</code>.
+ */
+ public ObjectImporter(Applet applet) {
+ URL codebase = applet.getCodeBase();
+ orgServername = servername = codebase.getHost();
+ orgPort = port = codebase.getPort();
+ }
+
+ /**
+ * Constructs an object importer.
+ *
+ * <p>If you run a program with <code>javassist.web.Viewer</code>,
+ * you can construct an object importer as follows:
+ *
+ * <ul><pre>
+ * Viewer v = (Viewer)this.getClass().getClassLoader();
+ * ObjectImporter oi = new ObjectImporter(v.getServer(), v.getPort());
+ * </pre></ul>
+ *
+ * @see javassist.web.Viewer
+ */
+ public ObjectImporter(String servername, int port) {
+ this.orgServername = this.servername = servername;
+ this.orgPort = this.port = port;
+ }
+
+ /**
+ * Finds the object exported by a server with the specified name.
+ * If the object is not found, this method returns null.
+ *
+ * @param name the name of the exported object.
+ * @return the proxy object or null.
+ */
+ public Object getObject(String name) {
+ try {
+ return lookupObject(name);
+ }
+ catch (ObjectNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Sets an http proxy server. After this method is called, the object
+ * importer connects a server through the http proxy server.
+ */
+ public void setHttpProxy(String host, int port) {
+ String proxyHeader = "POST http://" + orgServername + ":" + orgPort;
+ String cmd = proxyHeader + "/lookup HTTP/1.0";
+ lookupCommand = cmd.getBytes();
+ cmd = proxyHeader + "/rmi HTTP/1.0";
+ rmiCommand = cmd.getBytes();
+ this.servername = host;
+ this.port = port;
+ }
+
+ /**
+ * Finds the object exported by the server with the specified name.
+ * It sends a POST request to the server (via an http proxy server
+ * if needed).
+ *
+ * @param name the name of the exported object.
+ * @return the proxy object.
+ */
+ public Object lookupObject(String name) throws ObjectNotFoundException
+ {
+ try {
+ Socket sock = new Socket(servername, port);
+ OutputStream out = sock.getOutputStream();
+ out.write(lookupCommand);
+ out.write(endofline);
+ out.write(endofline);
+
+ ObjectOutputStream dout = new ObjectOutputStream(out);
+ dout.writeUTF(name);
+ dout.flush();
+
+ InputStream in = new BufferedInputStream(sock.getInputStream());
+ skipHeader(in);
+ ObjectInputStream din = new ObjectInputStream(in);
+ int n = din.readInt();
+ String classname = din.readUTF();
+ din.close();
+ dout.close();
+ sock.close();
+
+ if (n >= 0)
+ return createProxy(n, classname);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ throw new ObjectNotFoundException(name, e);
+ }
+
+ throw new ObjectNotFoundException(name);
+ }
+
+ private static final Class[] proxyConstructorParamTypes
+ = new Class[] { ObjectImporter.class, int.class };
+
+ private Object createProxy(int oid, String classname) throws Exception {
+ Class c = Class.forName(classname);
+ Constructor cons = c.getConstructor(proxyConstructorParamTypes);
+ return cons.newInstance(new Object[] { this, new Integer(oid) });
+ }
+
+ /**
+ * Calls a method on a remote object.
+ * It sends a POST request to the server (via an http proxy server
+ * if needed).
+ *
+ * <p>This method is called by only proxy objects.
+ */
+ public Object call(int objectid, int methodid, Object[] args)
+ throws RemoteException
+ {
+ boolean result;
+ Object rvalue;
+ String errmsg;
+
+ try {
+ /* This method establishes a raw tcp connection for sending
+ * a POST message. Thus the object cannot communicate a
+ * remote object beyond a fire wall. To avoid this problem,
+ * the connection should be established with a mechanism
+ * collaborating a proxy server. Unfortunately, java.lang.URL
+ * does not seem to provide such a mechanism.
+ *
+ * You might think that using HttpURLConnection is a better
+ * way than constructing a raw tcp connection. Unfortunately,
+ * URL.openConnection() does not return an HttpURLConnection
+ * object in Netscape's JVM. It returns a
+ * netscape.net.URLConnection object.
+ *
+ * lookupObject() has the same problem.
+ */
+ Socket sock = new Socket(servername, port);
+ OutputStream out = new BufferedOutputStream(
+ sock.getOutputStream());
+ out.write(rmiCommand);
+ out.write(endofline);
+ out.write(endofline);
+
+ ObjectOutputStream dout = new ObjectOutputStream(out);
+ dout.writeInt(objectid);
+ dout.writeInt(methodid);
+ writeParameters(dout, args);
+ dout.flush();
+
+ InputStream ins = new BufferedInputStream(sock.getInputStream());
+ skipHeader(ins);
+ ObjectInputStream din = new ObjectInputStream(ins);
+ result = din.readBoolean();
+ rvalue = null;
+ errmsg = null;
+ if (result)
+ rvalue = din.readObject();
+ else
+ errmsg = din.readUTF();
+
+ din.close();
+ dout.close();
+ sock.close();
+
+ if (rvalue instanceof RemoteRef) {
+ RemoteRef ref = (RemoteRef)rvalue;
+ rvalue = createProxy(ref.oid, ref.classname);
+ }
+ }
+ catch (ClassNotFoundException e) {
+ throw new RemoteException(e);
+ }
+ catch (IOException e) {
+ throw new RemoteException(e);
+ }
+ catch (Exception e) {
+ throw new RemoteException(e);
+ }
+
+ if (result)
+ return rvalue;
+ else
+ throw new RemoteException(errmsg);
+ }
+
+ private void skipHeader(InputStream in) throws IOException {
+ int len;
+ do {
+ int c;
+ len = 0;
+ while ((c = in.read()) >= 0 && c != 0x0d)
+ ++len;
+
+ in.read(); /* skip 0x0a (LF) */
+ } while (len > 0);
+ }
+
+ private void writeParameters(ObjectOutputStream dout, Object[] params)
+ throws IOException
+ {
+ int n = params.length;
+ dout.writeInt(n);
+ for (int i = 0; i < n; ++i)
+ if (params[i] instanceof Proxy) {
+ Proxy p = (Proxy)params[i];
+ dout.writeObject(new RemoteRef(p._getObjectId()));
+ }
+ else
+ dout.writeObject(params[i]);
+ }
+}
diff --git a/src/main/javassist/rmi/ObjectNotFoundException.java b/src/main/javassist/rmi/ObjectNotFoundException.java
new file mode 100644
index 00000000..e31db370
--- /dev/null
+++ b/src/main/javassist/rmi/ObjectNotFoundException.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+public class ObjectNotFoundException extends Exception {
+ public ObjectNotFoundException(String name) {
+ super(name + " is not exported");
+ }
+
+ public ObjectNotFoundException(String name, Exception e) {
+ super(name + " because of " + e.toString());
+ }
+}
diff --git a/src/main/javassist/rmi/Proxy.java b/src/main/javassist/rmi/Proxy.java
new file mode 100644
index 00000000..f310d358
--- /dev/null
+++ b/src/main/javassist/rmi/Proxy.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+/**
+ * An interface implemented by proxy classes.
+ *
+ * @see javassist.rmi.StubGenerator
+ */
+public interface Proxy {
+ int _getObjectId();
+}
diff --git a/src/main/javassist/rmi/RemoteException.java b/src/main/javassist/rmi/RemoteException.java
new file mode 100644
index 00000000..6b89c64b
--- /dev/null
+++ b/src/main/javassist/rmi/RemoteException.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+/**
+ * <code>RemoteException</code> represents any exception thrown
+ * during remote method invocation.
+ */
+public class RemoteException extends RuntimeException {
+ public RemoteException(String msg) {
+ super(msg);
+ }
+
+ public RemoteException(Exception e) {
+ super("by " + e.toString());
+ }
+}
diff --git a/src/main/javassist/rmi/RemoteRef.java b/src/main/javassist/rmi/RemoteRef.java
new file mode 100644
index 00000000..0017ecc1
--- /dev/null
+++ b/src/main/javassist/rmi/RemoteRef.java
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+/**
+ * Remote reference. This class is internally used for sending a remote
+ * reference through a network stream.
+ */
+public class RemoteRef implements java.io.Serializable {
+ public int oid;
+ public String classname;
+
+ public RemoteRef(int i) {
+ oid = i;
+ classname = null;
+ }
+
+ public RemoteRef(int i, String name) {
+ oid = i;
+ classname = name;
+ }
+}
diff --git a/src/main/javassist/rmi/Sample.java b/src/main/javassist/rmi/Sample.java
new file mode 100644
index 00000000..fee85d27
--- /dev/null
+++ b/src/main/javassist/rmi/Sample.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+/**
+ * A template used for defining a proxy class.
+ * The class file of this class is read by the <code>StubGenerator</code>
+ * class.
+ */
+public class Sample {
+ private ObjectImporter importer;
+ private int objectId;
+
+ public Object forward(Object[] args, int identifier) {
+ return importer.call(objectId, identifier, args);
+ }
+
+ public static Object forwardStatic(Object[] args, int identifier)
+ throws RemoteException
+ {
+ throw new RemoteException("cannot call a static method.");
+ }
+}
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));
+ }
+ }
+}