/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