Home | History | Annotate | Download | only in rmi
      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 
     16 package javassist.tools.rmi;
     17 
     18 import java.io.*;
     19 
     20 import javassist.tools.web.*;
     21 import javassist.CannotCompileException;
     22 import javassist.NotFoundException;
     23 import javassist.ClassPool;
     24 import java.lang.reflect.Method;
     25 import java.util.Hashtable;
     26 import 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  */
     37 public 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 
    246 class ExportedObject {
    247     public int identifier;
    248     public Object object;
    249     public Method[] methods;
    250 }
    251