169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit.
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License.  Alternatively, the contents of this file may be used under
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later.
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis,
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License.
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.tools.rmi;
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.*;
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.tools.web.*;
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CannotCompileException;
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.NotFoundException;
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.ClassPool;
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.Method;
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Hashtable;
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Vector;
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * An AppletServer object is a web server that an ObjectImporter
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * communicates with.  It makes the objects specified by
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>exportObject()</code> remotely accessible from applets.
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If the classes of the exported objects are requested by the client-side
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * JVM, this web server sends proxy classes for the requested classes.
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.tools.rmi.ObjectImporter
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class AppletServer extends Webserver {
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private StubGenerator stubGen;
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Hashtable exportedNames;
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Vector exportedObjects;
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final byte[] okHeader
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                = "HTTP/1.0 200 OK\r\n\r\n".getBytes();
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a web server.
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param port      port number
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public AppletServer(String port)
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException, NotFoundException, CannotCompileException
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this(Integer.parseInt(port));
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a web server.
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param port      port number
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public AppletServer(int port)
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException, NotFoundException, CannotCompileException
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this(ClassPool.getDefault(), new StubGenerator(), port);
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs a web server.
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param port      port number
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param src       the source of classs files.
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public AppletServer(int port, ClassPool src)
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException, NotFoundException, CannotCompileException
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this(new ClassPool(src), new StubGenerator(), port);
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private AppletServer(ClassPool loader, StubGenerator gen, int port)
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException, NotFoundException, CannotCompileException
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        super(port);
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        exportedNames = new Hashtable();
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        exportedObjects = new Vector();
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        stubGen = gen;
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        addTranslator(loader, gen);
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Begins the HTTP service.
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void run() {
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        super.run();
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Exports an object.
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * This method produces the bytecode of the proxy class used
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * to access the exported object.  A remote applet can load
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * the proxy class and call a method on the exported object.
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param name      the name used for looking the object up.
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param obj       the exported object.
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return          the object identifier
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see javassist.tools.rmi.ObjectImporter#lookupObject(String)
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public synchronized int exportObject(String name, Object obj)
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class clazz = obj.getClass();
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ExportedObject eo = new ExportedObject();
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        eo.object = obj;
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        eo.methods = clazz.getMethods();
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        exportedObjects.addElement(eo);
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        eo.identifier = exportedObjects.size() - 1;
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (name != null)
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            exportedNames.put(name, eo);
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            stubGen.makeProxyClass(clazz);
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (NotFoundException e) {
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new CannotCompileException(e);
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return eo.identifier;
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Processes a request from a web browser (an ObjectImporter).
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void doReply(InputStream in, OutputStream out, String cmd)
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException, BadHttpRequest
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (cmd.startsWith("POST /rmi "))
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            processRMI(in, out);
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else if (cmd.startsWith("POST /lookup "))
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            lookupName(cmd, in, out);
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            super.doReply(in, out, cmd);
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void processRMI(InputStream ins, OutputStream outs)
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ObjectInputStream in = new ObjectInputStream(ins);
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int objectId = in.readInt();
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int methodId = in.readInt();
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Exception err = null;
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Object rvalue = null;
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ExportedObject eo
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                = (ExportedObject)exportedObjects.elementAt(objectId);
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Object[] args = readParameters(in);
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            rvalue = convertRvalue(eo.methods[methodId].invoke(eo.object,
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                                               args));
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch(Exception e) {
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            err = e;
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            logging2(e.toString());
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        outs.write(okHeader);
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ObjectOutputStream out = new ObjectOutputStream(outs);
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (err != null) {
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.writeBoolean(false);
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.writeUTF(err.toString());
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            try {
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                out.writeBoolean(true);
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                out.writeObject(rvalue);
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (NotSerializableException e) {
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                logging2(e.toString());
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            catch (InvalidClassException e) {
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                logging2(e.toString());
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.flush();
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.close();
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        in.close();
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Object[] readParameters(ObjectInputStream in)
18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException, ClassNotFoundException
19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int n = in.readInt();
19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Object[] args = new Object[n];
19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < n; ++i) {
19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Object a = in.readObject();
19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (a instanceof RemoteRef) {
19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                RemoteRef ref = (RemoteRef)a;
19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                ExportedObject eo
19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    = (ExportedObject)exportedObjects.elementAt(ref.oid);
19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                a = eo.object;
20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            args[i] = a;
20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return args;
20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Object convertRvalue(Object rvalue)
20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws CannotCompileException
21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (rvalue == null)
21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return null;        // the return type is void.
21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String classname = rvalue.getClass().getName();
21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (stubGen.isProxyClass(classname))
21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return new RemoteRef(exportObject(null, rvalue), classname);
21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return rvalue;
21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void lookupName(String cmd, InputStream ins, OutputStream outs)
22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException
22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ObjectInputStream in = new ObjectInputStream(ins);
22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String name = DataInputStream.readUTF(in);
22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ExportedObject found = (ExportedObject)exportedNames.get(name);
22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        outs.write(okHeader);
22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ObjectOutputStream out = new ObjectOutputStream(outs);
22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (found == null) {
23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            logging2(name + "not found.");
23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.writeInt(-1);           // error code
23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.writeUTF("error");
23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else {
23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            logging2(name);
23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.writeInt(found.identifier);
23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.writeUTF(found.object.getClass().getName());
23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.flush();
24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        out.close();
24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        in.close();
24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalclass ExportedObject {
24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public int identifier;
24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Object object;
24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Method[] methods;
25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
251