/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. Alternatively, the contents of this file may be used under
* the terms of the GNU Lesser General Public License Version 2.1 or later,
* or the Apache License Version 2.0.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*/
package javassist.tools.rmi;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.net.Socket;
import java.net.URL;
The object importer enables applets to call a method on a remote
object running on the Webserver
(the main class of this
package).
To access the remote
object, the applet first calls lookupObject()
and
obtains a proxy object, which is a reference to that object.
The class name of the proxy object is identical to that of
the remote object.
The proxy object provides the same set of methods as the remote object.
If one of the methods is invoked on the proxy object,
the invocation is delegated to the remote object.
From the viewpoint of the applet, therefore, the two objects are
identical. The applet can access the object on the server
with the regular Java syntax without concern about the actual
location.
The methods remotely called by the applet must be public
.
This is true even if the applet's class and the remote object's classs
belong to the same package.
If class X is a class of remote objects, a subclass of X must be
also a class of remote objects. On the other hand, this restriction
is not applied to the superclass of X. The class X does not have to
contain a constructor taking no arguments.
The parameters to a remote method is passed in the call-by-value
manner. Thus all the parameter classes must implement
java.io.Serializable
. However, if the parameter is the
proxy object, the reference to the remote object instead of a copy of
the object is passed to the method.
Because of the limitations of the current implementation,
- The parameter objects cannot contain the proxy
object as a field value.
- If class
C
is of the remote object, then
the applet cannot instantiate C
locally or remotely.
All the exceptions thrown by the remote object are converted
into RemoteException
. Since this exception is a subclass
of RuntimeException
, the caller method does not need
to catch the exception. However, good programs should catch
the RuntimeException
.
See Also: - AppletServer
- RemoteException
- Viewer
/**
* The object importer enables applets to call a method on a remote
* object running on the <code>Webserver</code> (the <b>main</b> class of this
* package).
*
* <p>To access the remote
* object, the applet first calls <code>lookupObject()</code> and
* obtains a proxy object, which is a reference to that object.
* The class name of the proxy object is identical to that of
* the remote object.
* The proxy object provides the same set of methods as the remote object.
* If one of the methods is invoked on the proxy object,
* the invocation is delegated to the remote object.
* From the viewpoint of the applet, therefore, the two objects are
* identical. The applet can access the object on the server
* with the regular Java syntax without concern about the actual
* location.
*
* <p>The methods remotely called by the applet must be <code>public</code>.
* This is true even if the applet's class and the remote object's classs
* belong to the same package.
*
* <p>If class X is a class of remote objects, a subclass of X must be
* also a class of remote objects. On the other hand, this restriction
* is not applied to the superclass of X. The class X does not have to
* contain a constructor taking no arguments.
*
* <p>The parameters to a remote method is passed in the <i>call-by-value</i>
* manner. Thus all the parameter classes must implement
* <code>java.io.Serializable</code>. However, if the parameter is the
* proxy object, the reference to the remote object instead of a copy of
* the object is passed to the method.
*
* <p>Because of the limitations of the current implementation,
* <ul>
* <li>The parameter objects cannot contain the proxy
* object as a field value.
* <li>If class <code>C</code> is of the remote object, then
* the applet cannot instantiate <code>C</code> locally or remotely.
* </ul>
*
* <p>All the exceptions thrown by the remote object are converted
* into <code>RemoteException</code>. Since this exception is a subclass
* of <code>RuntimeException</code>, the caller method does not need
* to catch the exception. However, good programs should catch
* the <code>RuntimeException</code>.
*
* @see javassist.tools.rmi.AppletServer
* @see javassist.tools.rmi.RemoteException
* @see javassist.tools.web.Viewer
*/
public class ObjectImporter implements java.io.Serializable {
default serialVersionUID /** default serialVersionUID */
private static final long serialVersionUID = 1L;
private final byte[] endofline = { 0x0d, 0x0a };
private String servername, orgServername;
private int port, orgPort;
protected byte[] lookupCommand = "POST /lookup HTTP/1.0".getBytes();
protected byte[] rmiCommand = "POST /rmi HTTP/1.0".getBytes();
Constructs an object importer.
Remote objects are imported from the web server that the given
applet has been loaded from.
Params: - applet – the applet loaded from the
Webserver
.
/**
* Constructs an object importer.
*
* <p>Remote objects are imported from the web server that the given
* applet has been loaded from.
*
* @param applet the applet loaded from the <code>Webserver</code>.
*/
public ObjectImporter(@SuppressWarnings("deprecation") java.applet.Applet applet) {
@SuppressWarnings("deprecation")
URL codebase = applet.getCodeBase();
orgServername = servername = codebase.getHost();
orgPort = port = codebase.getPort();
}
Constructs an object importer.
If you run a program with javassist.tools.web.Viewer
,
you can construct an object importer as follows:
Viewer v = (Viewer)this.getClass().getClassLoader();
ObjectImporter oi = new ObjectImporter(v.getServer(), v.getPort());
See Also: - Viewer
/**
* Constructs an object importer.
*
* <p>If you run a program with <code>javassist.tools.web.Viewer</code>,
* you can construct an object importer as follows:
*
* <pre>
* Viewer v = (Viewer)this.getClass().getClassLoader();
* ObjectImporter oi = new ObjectImporter(v.getServer(), v.getPort());
* </pre>
*
* @see javassist.tools.web.Viewer
*/
public ObjectImporter(String servername, int port) {
this.orgServername = this.servername = servername;
this.orgPort = this.port = port;
}
Finds the object exported by a server with the specified name.
If the object is not found, this method returns null.
Params: - name – the name of the exported object.
Returns: the proxy object or null.
/**
* Finds the object exported by a server with the specified name.
* If the object is not found, this method returns null.
*
* @param name the name of the exported object.
* @return the proxy object or null.
*/
public Object getObject(String name) {
try {
return lookupObject(name);
}
catch (ObjectNotFoundException e) {
return null;
}
}
Sets an http proxy server. After this method is called, the object
importer connects a server through the http proxy server.
/**
* Sets an http proxy server. After this method is called, the object
* importer connects a server through the http proxy server.
*/
public void setHttpProxy(String host, int port) {
String proxyHeader = "POST http://" + orgServername + ":" + orgPort;
String cmd = proxyHeader + "/lookup HTTP/1.0";
lookupCommand = cmd.getBytes();
cmd = proxyHeader + "/rmi HTTP/1.0";
rmiCommand = cmd.getBytes();
this.servername = host;
this.port = port;
}
Finds the object exported by the server with the specified name.
It sends a POST request to the server (via an http proxy server
if needed).
Params: - name – the name of the exported object.
Returns: the proxy object.
/**
* Finds the object exported by the server with the specified name.
* It sends a POST request to the server (via an http proxy server
* if needed).
*
* @param name the name of the exported object.
* @return the proxy object.
*/
public Object lookupObject(String name) throws ObjectNotFoundException
{
try {
Socket sock = new Socket(servername, port);
OutputStream out = sock.getOutputStream();
out.write(lookupCommand);
out.write(endofline);
out.write(endofline);
ObjectOutputStream dout = new ObjectOutputStream(out);
dout.writeUTF(name);
dout.flush();
InputStream in = new BufferedInputStream(sock.getInputStream());
skipHeader(in);
ObjectInputStream din = new ObjectInputStream(in);
int n = din.readInt();
String classname = din.readUTF();
din.close();
dout.close();
sock.close();
if (n >= 0)
return createProxy(n, classname);
}
catch (Exception e) {
e.printStackTrace();
throw new ObjectNotFoundException(name, e);
}
throw new ObjectNotFoundException(name);
}
private static final Class<?>[] proxyConstructorParamTypes
= new Class[] { ObjectImporter.class, int.class };
private Object createProxy(int oid, String classname) throws Exception {
Class<?> c = Class.forName(classname);
Constructor<?> cons = c.getConstructor(proxyConstructorParamTypes);
return cons.newInstance(new Object[] { this, Integer.valueOf(oid) });
}
Calls a method on a remote object.
It sends a POST request to the server (via an http proxy server
if needed).
This method is called by only proxy objects.
/**
* Calls a method on a remote object.
* It sends a POST request to the server (via an http proxy server
* if needed).
*
* <p>This method is called by only proxy objects.
*/
public Object call(int objectid, int methodid, Object[] args)
throws RemoteException
{
boolean result;
Object rvalue;
String errmsg;
try {
/* This method establishes a raw tcp connection for sending
* a POST message. Thus the object cannot communicate a
* remote object beyond a fire wall. To avoid this problem,
* the connection should be established with a mechanism
* collaborating a proxy server. Unfortunately, java.lang.URL
* does not seem to provide such a mechanism.
*
* You might think that using HttpURLConnection is a better
* way than constructing a raw tcp connection. Unfortunately,
* URL.openConnection() does not return an HttpURLConnection
* object in Netscape's JVM. It returns a
* netscape.net.URLConnection object.
*
* lookupObject() has the same problem.
*/
Socket sock = new Socket(servername, port);
OutputStream out = new BufferedOutputStream(
sock.getOutputStream());
out.write(rmiCommand);
out.write(endofline);
out.write(endofline);
ObjectOutputStream dout = new ObjectOutputStream(out);
dout.writeInt(objectid);
dout.writeInt(methodid);
writeParameters(dout, args);
dout.flush();
InputStream ins = new BufferedInputStream(sock.getInputStream());
skipHeader(ins);
ObjectInputStream din = new ObjectInputStream(ins);
result = din.readBoolean();
rvalue = null;
errmsg = null;
if (result)
rvalue = din.readObject();
else
errmsg = din.readUTF();
din.close();
dout.close();
sock.close();
if (rvalue instanceof RemoteRef) {
RemoteRef ref = (RemoteRef)rvalue;
rvalue = createProxy(ref.oid, ref.classname);
}
}
catch (ClassNotFoundException e) {
throw new RemoteException(e);
}
catch (IOException e) {
throw new RemoteException(e);
}
catch (Exception e) {
throw new RemoteException(e);
}
if (result)
return rvalue;
throw new RemoteException(errmsg);
}
private void skipHeader(InputStream in) throws IOException {
int len;
do {
int c;
len = 0;
while ((c = in.read()) >= 0 && c != 0x0d)
++len;
in.read(); /* skip 0x0a (LF) */
} while (len > 0);
}
private void writeParameters(ObjectOutputStream dout, Object[] params)
throws IOException
{
int n = params.length;
dout.writeInt(n);
for (int i = 0; i < n; ++i)
if (params[i] instanceof Proxy) {
Proxy p = (Proxy)params[i];
dout.writeObject(new RemoteRef(p._getObjectId()));
}
else
dout.writeObject(params[i]);
}
}