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 Sigalimport java.net.*;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.applet.Applet;
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.reflect.*;
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The object importer enables applets to call a method on a remote
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * object running on the <code>Webserver</code> (the <b>main</b> class of this
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * package).
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>To access the remote
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * object, the applet first calls <code>lookupObject()</code> and
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * obtains a proxy object, which is a reference to that object.
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The class name of the proxy object is identical to that of
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the remote object.
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The proxy object provides the same set of methods as the remote object.
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If one of the methods is invoked on the proxy object,
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the invocation is delegated to the remote object.
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * From the viewpoint of the applet, therefore, the two objects are
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * identical. The applet can access the object on the server
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * with the regular Java syntax without concern about the actual
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * location.
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>The methods remotely called by the applet must be <code>public</code>.
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * This is true even if the applet's class and the remote object's classs
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * belong to the same package.
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>If class X is a class of remote objects, a subclass of X must be
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * also a class of remote objects.  On the other hand, this restriction
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * is not applied to the superclass of X.  The class X does not have to
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * contain a constructor taking no arguments.
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>The parameters to a remote method is passed in the <i>call-by-value</i>
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * manner.  Thus all the parameter classes must implement
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>java.io.Serializable</code>.  However, if the parameter is the
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * proxy object, the reference to the remote object instead of a copy of
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the object is passed to the method.
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>Because of the limitations of the current implementation,
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul>
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <li>The parameter objects cannot contain the proxy
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * object as a field value.
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <li>If class <code>C</code> is of the remote object, then
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the applet cannot instantiate <code>C</code> locally or remotely.
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </ul>
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>All the exceptions thrown by the remote object are converted
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * into <code>RemoteException</code>.  Since this exception is a subclass
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * of <code>RuntimeException</code>, the caller method does not need
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * to catch the exception.  However, good programs should catch
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the <code>RuntimeException</code>.
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.tools.rmi.AppletServer
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.tools.rmi.RemoteException
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.tools.web.Viewer
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class ObjectImporter implements java.io.Serializable {
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private final byte[] endofline = { 0x0d, 0x0a };
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private String servername, orgServername;
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private int port, orgPort;
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected byte[] lookupCommand = "POST /lookup HTTP/1.0".getBytes();
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected byte[] rmiCommand = "POST /rmi HTTP/1.0".getBytes();
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs an object importer.
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>Remote objects are imported from the web server that the given
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * applet has been loaded from.
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param applet    the applet loaded from the <code>Webserver</code>.
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public ObjectImporter(Applet applet) {
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        URL codebase = applet.getCodeBase();
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        orgServername = servername = codebase.getHost();
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        orgPort = port = codebase.getPort();
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Constructs an object importer.
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>If you run a program with <code>javassist.tools.web.Viewer</code>,
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * you can construct an object importer as follows:
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <ul><pre>
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Viewer v = (Viewer)this.getClass().getClassLoader();
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * ObjectImporter oi = new ObjectImporter(v.getServer(), v.getPort());
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * </pre></ul>
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @see javassist.tools.web.Viewer
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public ObjectImporter(String servername, int port) {
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.orgServername = this.servername = servername;
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.orgPort = this.port = port;
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Finds the object exported by a server with the specified name.
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * If the object is not found, this method returns null.
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param name      the name of the exported object.
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return          the proxy object or null.
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Object getObject(String name) {
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return lookupObject(name);
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (ObjectNotFoundException e) {
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return null;
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Sets an http proxy server.  After this method is called, the object
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * importer connects a server through the http proxy server.
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setHttpProxy(String host, int port) {
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String proxyHeader = "POST http://" + orgServername + ":" + orgPort;
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String cmd = proxyHeader + "/lookup HTTP/1.0";
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        lookupCommand = cmd.getBytes();
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        cmd = proxyHeader + "/rmi HTTP/1.0";
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        rmiCommand = cmd.getBytes();
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.servername = host;
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.port = port;
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Finds the object exported by the server with the specified name.
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * It sends a POST request to the server (via an http proxy server
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * if needed).
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param name      the name of the exported object.
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return          the proxy object.
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Object lookupObject(String name) throws ObjectNotFoundException
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Socket sock = new Socket(servername, port);
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            OutputStream out = sock.getOutputStream();
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.write(lookupCommand);
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.write(endofline);
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.write(endofline);
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ObjectOutputStream dout = new ObjectOutputStream(out);
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            dout.writeUTF(name);
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            dout.flush();
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            InputStream in = new BufferedInputStream(sock.getInputStream());
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            skipHeader(in);
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ObjectInputStream din = new ObjectInputStream(in);
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int n = din.readInt();
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            String classname = din.readUTF();
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            din.close();
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            dout.close();
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            sock.close();
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (n >= 0)
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return createProxy(n, classname);
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (Exception e) {
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            e.printStackTrace();
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new ObjectNotFoundException(name, e);
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throw new ObjectNotFoundException(name);
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final Class[] proxyConstructorParamTypes
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        = new Class[] { ObjectImporter.class, int.class };
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Object createProxy(int oid, String classname) throws Exception {
18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Class c = Class.forName(classname);
19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Constructor cons = c.getConstructor(proxyConstructorParamTypes);
19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return cons.newInstance(new Object[] { this, new Integer(oid) });
19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Calls a method on a remote object.
19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * It sends a POST request to the server (via an http proxy server
19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * if needed).
19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * <p>This method is called by only proxy objects.
20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Object call(int objectid, int methodid, Object[] args)
20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws RemoteException
20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        boolean result;
20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Object rvalue;
20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        String errmsg;
20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        try {
20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            /* This method establishes a raw tcp connection for sending
21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             * a POST message.  Thus the object cannot communicate a
21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             * remote object beyond a fire wall.  To avoid this problem,
21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             * the connection should be established with a mechanism
21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             * collaborating a proxy server.  Unfortunately, java.lang.URL
21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             * does not seem to provide such a mechanism.
21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             *
21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             * You might think that using HttpURLConnection is a better
21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             * way than constructing a raw tcp connection.  Unfortunately,
21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             * URL.openConnection() does not return an HttpURLConnection
21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             * object in Netscape's JVM.  It returns a
22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             * netscape.net.URLConnection object.
22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             *
22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             * lookupObject() has the same problem.
22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal             */
22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Socket sock = new Socket(servername, port);
22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            OutputStream out = new BufferedOutputStream(
22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                                sock.getOutputStream());
22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.write(rmiCommand);
22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.write(endofline);
22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            out.write(endofline);
23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ObjectOutputStream dout = new ObjectOutputStream(out);
23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            dout.writeInt(objectid);
23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            dout.writeInt(methodid);
23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            writeParameters(dout, args);
23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            dout.flush();
23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            InputStream ins = new BufferedInputStream(sock.getInputStream());
23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            skipHeader(ins);
23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ObjectInputStream din = new ObjectInputStream(ins);
24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            result = din.readBoolean();
24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            rvalue = null;
24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            errmsg = null;
24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (result)
24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                rvalue = din.readObject();
24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else
24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                errmsg = din.readUTF();
24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            din.close();
24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            dout.close();
25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            sock.close();
25169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
25269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (rvalue instanceof RemoteRef) {
25369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                RemoteRef ref = (RemoteRef)rvalue;
25469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                rvalue = createProxy(ref.oid, ref.classname);
25569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
25669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
25769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (ClassNotFoundException e) {
25869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RemoteException(e);
25969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
26069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (IOException e) {
26169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RemoteException(e);
26269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
26369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        catch (Exception e) {
26469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RemoteException(e);
26569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
26669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
26769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (result)
26869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return rvalue;
26969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else
27069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            throw new RemoteException(errmsg);
27169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
27269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
27369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void skipHeader(InputStream in) throws IOException {
27469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int len;
27569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        do {
27669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            int c;
27769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            len = 0;
27869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            while ((c = in.read()) >= 0 && c != 0x0d)
27969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                ++len;
28069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
28169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            in.read();  /* skip 0x0a (LF) */
28269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        } while (len > 0);
28369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
28469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
28569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void writeParameters(ObjectOutputStream dout, Object[] params)
28669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throws IOException
28769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    {
28869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        int n = params.length;
28969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        dout.writeInt(n);
29069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        for (int i = 0; i < n; ++i)
29169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (params[i] instanceof Proxy) {
29269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                Proxy p = (Proxy)params[i];
29369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                dout.writeObject(new RemoteRef(p._getObjectId()));
29469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
29569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            else
29669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                dout.writeObject(params[i]);
29769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
29869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
299