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 java.io.*;
019:
020: import javassist.tools.web.*;
021: import javassist.CannotCompileException;
022: import javassist.NotFoundException;
023: import javassist.ClassPool;
024: import java.lang.reflect.Method;
025: import java.util.Hashtable;
026: import java.util.Vector;
027:
028: /**
029: * An AppletServer object is a web server that an ObjectImporter
030: * communicates with. It makes the objects specified by
031: * <code>exportObject()</code> remotely accessible from applets.
032: * If the classes of the exported objects are requested by the client-side
033: * JVM, this web server sends proxy classes for the requested classes.
034: *
035: * @see javassist.tools.rmi.ObjectImporter
036: */
037: public class AppletServer extends Webserver {
038: private StubGenerator stubGen;
039: private Hashtable exportedNames;
040: private Vector exportedObjects;
041:
042: private static final byte[] okHeader = "HTTP/1.0 200 OK\r\n\r\n"
043: .getBytes();
044:
045: /**
046: * Constructs a web server.
047: *
048: * @param port port number
049: */
050: public AppletServer(String port) throws IOException,
051: NotFoundException, CannotCompileException {
052: this (Integer.parseInt(port));
053: }
054:
055: /**
056: * Constructs a web server.
057: *
058: * @param port port number
059: */
060: public AppletServer(int port) throws IOException,
061: NotFoundException, CannotCompileException {
062: this (ClassPool.getDefault(), new StubGenerator(), port);
063: }
064:
065: /**
066: * Constructs a web server.
067: *
068: * @param port port number
069: * @param src the source of classs files.
070: */
071: public AppletServer(int port, ClassPool src) throws IOException,
072: NotFoundException, CannotCompileException {
073: this (new ClassPool(src), new StubGenerator(), port);
074: }
075:
076: private AppletServer(ClassPool loader, StubGenerator gen, int port)
077: throws IOException, NotFoundException,
078: CannotCompileException {
079: super (port);
080: exportedNames = new Hashtable();
081: exportedObjects = new Vector();
082: stubGen = gen;
083: addTranslator(loader, gen);
084: }
085:
086: /**
087: * Begins the HTTP service.
088: */
089: public void run() {
090: super .run();
091: }
092:
093: /**
094: * Exports an object.
095: * This method produces the bytecode of the proxy class used
096: * to access the exported object. A remote applet can load
097: * the proxy class and call a method on the exported object.
098: *
099: * @param name the name used for looking the object up.
100: * @param obj the exported object.
101: * @return the object identifier
102: *
103: * @see javassist.tools.rmi.ObjectImporter#lookupObject(String)
104: */
105: public synchronized int exportObject(String name, Object obj)
106: throws CannotCompileException {
107: Class clazz = obj.getClass();
108: ExportedObject eo = new ExportedObject();
109: eo.object = obj;
110: eo.methods = clazz.getMethods();
111: exportedObjects.addElement(eo);
112: eo.identifier = exportedObjects.size() - 1;
113: if (name != null)
114: exportedNames.put(name, eo);
115:
116: try {
117: stubGen.makeProxyClass(clazz);
118: } catch (NotFoundException e) {
119: throw new CannotCompileException(e);
120: }
121:
122: return eo.identifier;
123: }
124:
125: /**
126: * Processes a request from a web browser (an ObjectImporter).
127: */
128: public void doReply(InputStream in, OutputStream out, String cmd)
129: throws IOException, BadHttpRequest {
130: if (cmd.startsWith("POST /rmi "))
131: processRMI(in, out);
132: else if (cmd.startsWith("POST /lookup "))
133: lookupName(cmd, in, out);
134: else
135: super .doReply(in, out, cmd);
136: }
137:
138: private void processRMI(InputStream ins, OutputStream outs)
139: throws IOException {
140: ObjectInputStream in = new ObjectInputStream(ins);
141:
142: int objectId = in.readInt();
143: int methodId = in.readInt();
144: Exception err = null;
145: Object rvalue = null;
146: try {
147: ExportedObject eo = (ExportedObject) exportedObjects
148: .elementAt(objectId);
149: Object[] args = readParameters(in);
150: rvalue = convertRvalue(eo.methods[methodId].invoke(
151: eo.object, args));
152: } catch (Exception e) {
153: err = e;
154: logging2(e.toString());
155: }
156:
157: outs.write(okHeader);
158: ObjectOutputStream out = new ObjectOutputStream(outs);
159: if (err != null) {
160: out.writeBoolean(false);
161: out.writeUTF(err.toString());
162: } else
163: try {
164: out.writeBoolean(true);
165: out.writeObject(rvalue);
166: } catch (NotSerializableException e) {
167: logging2(e.toString());
168: } catch (InvalidClassException e) {
169: logging2(e.toString());
170: }
171:
172: out.flush();
173: out.close();
174: in.close();
175: }
176:
177: private Object[] readParameters(ObjectInputStream in)
178: throws IOException, ClassNotFoundException {
179: int n = in.readInt();
180: Object[] args = new Object[n];
181: for (int i = 0; i < n; ++i) {
182: Object a = in.readObject();
183: if (a instanceof RemoteRef) {
184: RemoteRef ref = (RemoteRef) a;
185: ExportedObject eo = (ExportedObject) exportedObjects
186: .elementAt(ref.oid);
187: a = eo.object;
188: }
189:
190: args[i] = a;
191: }
192:
193: return args;
194: }
195:
196: private Object convertRvalue(Object rvalue)
197: throws CannotCompileException {
198: if (rvalue == null)
199: return null; // the return type is void.
200:
201: String classname = rvalue.getClass().getName();
202: if (stubGen.isProxyClass(classname))
203: return new RemoteRef(exportObject(null, rvalue), classname);
204: else
205: return rvalue;
206: }
207:
208: private void lookupName(String cmd, InputStream ins,
209: OutputStream outs) throws IOException {
210: ObjectInputStream in = new ObjectInputStream(ins);
211: String name = DataInputStream.readUTF(in);
212: ExportedObject found = (ExportedObject) exportedNames.get(name);
213: outs.write(okHeader);
214: ObjectOutputStream out = new ObjectOutputStream(outs);
215: if (found == null) {
216: logging2(name + "not found.");
217: out.writeInt(-1); // error code
218: out.writeUTF("error");
219: } else {
220: logging2(name);
221: out.writeInt(found.identifier);
222: out.writeUTF(found.object.getClass().getName());
223: }
224:
225: out.flush();
226: out.close();
227: in.close();
228: }
229: }
230:
231: class ExportedObject {
232: public int identifier;
233: public Object object;
234: public Method[] methods;
235: }
|