1/* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999-2007 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 16package javassist.tools.rmi; 17 18import java.io.*; 19 20import javassist.tools.web.*; 21import javassist.CannotCompileException; 22import javassist.NotFoundException; 23import javassist.ClassPool; 24import java.lang.reflect.Method; 25import java.util.Hashtable; 26import java.util.Vector; 27 28/** 29 * An AppletServer object is a web server that an ObjectImporter 30 * communicates with. It makes the objects specified by 31 * <code>exportObject()</code> remotely accessible from applets. 32 * If the classes of the exported objects are requested by the client-side 33 * JVM, this web server sends proxy classes for the requested classes. 34 * 35 * @see javassist.tools.rmi.ObjectImporter 36 */ 37public class AppletServer extends Webserver { 38 private StubGenerator stubGen; 39 private Hashtable exportedNames; 40 private Vector exportedObjects; 41 42 private static final byte[] okHeader 43 = "HTTP/1.0 200 OK\r\n\r\n".getBytes(); 44 45 /** 46 * Constructs a web server. 47 * 48 * @param port port number 49 */ 50 public AppletServer(String port) 51 throws IOException, NotFoundException, CannotCompileException 52 { 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 { 64 this(ClassPool.getDefault(), new StubGenerator(), port); 65 } 66 67 /** 68 * Constructs a web server. 69 * 70 * @param port port number 71 * @param src the source of classs files. 72 */ 73 public AppletServer(int port, ClassPool src) 74 throws IOException, NotFoundException, CannotCompileException 75 { 76 this(new ClassPool(src), new StubGenerator(), port); 77 } 78 79 private AppletServer(ClassPool loader, StubGenerator gen, int port) 80 throws IOException, NotFoundException, CannotCompileException 81 { 82 super(port); 83 exportedNames = new Hashtable(); 84 exportedObjects = new Vector(); 85 stubGen = gen; 86 addTranslator(loader, gen); 87 } 88 89 /** 90 * Begins the HTTP service. 91 */ 92 public void run() { 93 super.run(); 94 } 95 96 /** 97 * Exports an object. 98 * This method produces the bytecode of the proxy class used 99 * to access the exported object. A remote applet can load 100 * the proxy class and call a method on the exported object. 101 * 102 * @param name the name used for looking the object up. 103 * @param obj the exported object. 104 * @return the object identifier 105 * 106 * @see javassist.tools.rmi.ObjectImporter#lookupObject(String) 107 */ 108 public synchronized int exportObject(String name, Object obj) 109 throws CannotCompileException 110 { 111 Class clazz = obj.getClass(); 112 ExportedObject eo = new ExportedObject(); 113 eo.object = obj; 114 eo.methods = clazz.getMethods(); 115 exportedObjects.addElement(eo); 116 eo.identifier = exportedObjects.size() - 1; 117 if (name != null) 118 exportedNames.put(name, eo); 119 120 try { 121 stubGen.makeProxyClass(clazz); 122 } 123 catch (NotFoundException e) { 124 throw new CannotCompileException(e); 125 } 126 127 return eo.identifier; 128 } 129 130 /** 131 * Processes a request from a web browser (an ObjectImporter). 132 */ 133 public void doReply(InputStream in, OutputStream out, String cmd) 134 throws IOException, BadHttpRequest 135 { 136 if (cmd.startsWith("POST /rmi ")) 137 processRMI(in, out); 138 else if (cmd.startsWith("POST /lookup ")) 139 lookupName(cmd, in, out); 140 else 141 super.doReply(in, out, cmd); 142 } 143 144 private void processRMI(InputStream ins, OutputStream outs) 145 throws IOException 146 { 147 ObjectInputStream in = new ObjectInputStream(ins); 148 149 int objectId = in.readInt(); 150 int methodId = in.readInt(); 151 Exception err = null; 152 Object rvalue = null; 153 try { 154 ExportedObject eo 155 = (ExportedObject)exportedObjects.elementAt(objectId); 156 Object[] args = readParameters(in); 157 rvalue = convertRvalue(eo.methods[methodId].invoke(eo.object, 158 args)); 159 } 160 catch(Exception e) { 161 err = e; 162 logging2(e.toString()); 163 } 164 165 outs.write(okHeader); 166 ObjectOutputStream out = new ObjectOutputStream(outs); 167 if (err != null) { 168 out.writeBoolean(false); 169 out.writeUTF(err.toString()); 170 } 171 else 172 try { 173 out.writeBoolean(true); 174 out.writeObject(rvalue); 175 } 176 catch (NotSerializableException e) { 177 logging2(e.toString()); 178 } 179 catch (InvalidClassException e) { 180 logging2(e.toString()); 181 } 182 183 out.flush(); 184 out.close(); 185 in.close(); 186 } 187 188 private Object[] readParameters(ObjectInputStream in) 189 throws IOException, ClassNotFoundException 190 { 191 int n = in.readInt(); 192 Object[] args = new Object[n]; 193 for (int i = 0; i < n; ++i) { 194 Object a = in.readObject(); 195 if (a instanceof RemoteRef) { 196 RemoteRef ref = (RemoteRef)a; 197 ExportedObject eo 198 = (ExportedObject)exportedObjects.elementAt(ref.oid); 199 a = eo.object; 200 } 201 202 args[i] = a; 203 } 204 205 return args; 206 } 207 208 private Object convertRvalue(Object rvalue) 209 throws CannotCompileException 210 { 211 if (rvalue == null) 212 return null; // the return type is void. 213 214 String classname = rvalue.getClass().getName(); 215 if (stubGen.isProxyClass(classname)) 216 return new RemoteRef(exportObject(null, rvalue), classname); 217 else 218 return rvalue; 219 } 220 221 private void lookupName(String cmd, InputStream ins, OutputStream outs) 222 throws IOException 223 { 224 ObjectInputStream in = new ObjectInputStream(ins); 225 String name = DataInputStream.readUTF(in); 226 ExportedObject found = (ExportedObject)exportedNames.get(name); 227 outs.write(okHeader); 228 ObjectOutputStream out = new ObjectOutputStream(outs); 229 if (found == null) { 230 logging2(name + "not found."); 231 out.writeInt(-1); // error code 232 out.writeUTF("error"); 233 } 234 else { 235 logging2(name); 236 out.writeInt(found.identifier); 237 out.writeUTF(found.object.getClass().getName()); 238 } 239 240 out.flush(); 241 out.close(); 242 in.close(); 243 } 244} 245 246class ExportedObject { 247 public int identifier; 248 public Object object; 249 public Method[] methods; 250} 251