/Users/lyon/j4p/src/javassist/rmi/AppletServer.java
|
1 /*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16 package javassist.rmi;
17
18 import javassist.CannotCompileException;
19 import javassist.ClassPool;
20 import javassist.NotFoundException;
21 import javassist.web.BadHttpRequest;
22 import javassist.web.Webserver;
23
24 import java.io.*;
25 import java.lang.reflect.Method;
26 import java.util.Hashtable;
27 import java.util.Vector;
28
29 /**
30 * An AppletServer object is a web server that an ObjectImporter
31 * communicates with. It makes the objects specified by
32 * <code>exportObject()</code> remotely accessible from applets.
33 * If the classes of the exported objects are requested by the client-side
34 * JVM, this web server sends proxy classes for the requested classes.
35 *
36 * @see javassist.rmi.ObjectImporter
37 */
38 public class AppletServer extends Webserver {
39 private StubGenerator stubGen;
40 private Hashtable exportedNames;
41 private Vector exportedObjects;
42
43 private static final byte[] okHeader
44 = "HTTP/1.0 200 OK\r\n\r\n".getBytes();
45
46 /**
47 * Constructs a web server.
48 *
49 * @param port port number
50 */
51 public AppletServer(String port)
52 throws IOException, NotFoundException, CannotCompileException {
53 this(Integer.parseInt(port));
54 }
55
56 /**
57 * Constructs a web server.
58 *
59 * @param port port number
60 */
61 public AppletServer(int port)
62 throws IOException, NotFoundException, CannotCompileException {
63 this(ClassPool.getDefault(new StubGenerator()), port);
64 }
65
66 /**
67 * Constructs a web server.
68 *
69 * @param port port number
70 * @param src the source o?f classs files.
71 */
72 public AppletServer(int port, ClassPool src)
73 throws IOException, NotFoundException, CannotCompileException {
74 this(new ClassPool(src, new StubGenerator()), port);
75 }
76
77 private AppletServer(ClassPool loader, int port)
78 throws IOException {
79 super(port);
80 exportedNames = new Hashtable();
81 exportedObjects = new Vector();
82 stubGen = (StubGenerator) loader.getTranslator();
83 setClassPool(loader);
84 }
85
86 /**
87 * Begins the HTTP service.
88 */
89 public void run() {
90 super.run();
91 }
92
93 /**
94 * Exports an object.
95 * This method produces the bytecode of the proxy class used
96 * to access the exported object. A remote applet can load
97 * the proxy class and call a method on the exported object.
98 *
99 * @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.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
148 = (ExportedObject) exportedObjects.elementAt(objectId);
149 Object[] args = readParameters(in);
150 rvalue = convertRvalue(eo.methods[methodId].invoke(eo.object,
151 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
186 = (ExportedObject) exportedObjects.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, OutputStream outs)
209 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 }
236