/*
* 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.*;
import javassist.tools.web.*;
import javassist.
CannotCompileException;
import javassist.
NotFoundException;
import javassist.
ClassPool;
import java.lang.reflect.
Method;
import java.util.
Hashtable;
import java.util.
Vector;
/**
* An AppletServer object is a web server that an ObjectImporter
* communicates with. It makes the objects specified by
* <code>exportObject()</code> remotely accessible from applets.
* If the classes of the exported objects are requested by the client-side
* JVM, this web server sends proxy classes for the requested classes.
*
* @see javassist.tools.rmi.ObjectImporter
*/
public class
AppletServer extends
Webserver {
private
StubGenerator stubGen;
private
Hashtable exportedNames;
private
Vector exportedObjects;
private static final byte[]
okHeader
= "HTTP/1.0 200 OK\r\n\r\n".
getBytes();
/**
* Constructs a web server.
*
* @param port port number
*/
public
AppletServer(
String port)
throws
IOException,
NotFoundException,
CannotCompileException
{
this(
Integer.
parseInt(
port));
}
/**
* Constructs a web server.
*
* @param port port number
*/
public
AppletServer(int
port)
throws
IOException,
NotFoundException,
CannotCompileException
{
this(
ClassPool.
getDefault(), new
StubGenerator(),
port);
}
/**
* Constructs a web server.
*
* @param port port number
* @param src the source of classs files.
*/
public
AppletServer(int
port,
ClassPool src)
throws
IOException,
NotFoundException,
CannotCompileException
{
this(new
ClassPool(
src), new
StubGenerator(),
port);
}
private
AppletServer(
ClassPool loader,
StubGenerator gen, int
port)
throws
IOException,
NotFoundException,
CannotCompileException
{
super(
port);
exportedNames = new
Hashtable();
exportedObjects = new
Vector();
stubGen =
gen;
addTranslator(
loader,
gen);
}
/**
* Begins the HTTP service.
*/
public void
run() {
super.run();
}
/**
* Exports an object.
* This method produces the bytecode of the proxy class used
* to access the exported object. A remote applet can load
* the proxy class and call a method on the exported object.
*
* @param name the name used for looking the object up.
* @param obj the exported object.
* @return the object identifier
*
* @see javassist.tools.rmi.ObjectImporter#lookupObject(String)
*/
public synchronized int
exportObject(
String name,
Object obj)
throws
CannotCompileException
{
Class clazz =
obj.
getClass();
ExportedObject eo = new
ExportedObject();
eo.
object =
obj;
eo.
methods =
clazz.
getMethods();
exportedObjects.
addElement(
eo);
eo.
identifier =
exportedObjects.
size() - 1;
if (
name != null)
exportedNames.
put(
name,
eo);
try {
stubGen.
makeProxyClass(
clazz);
}
catch (
NotFoundException e) {
throw new
CannotCompileException(
e);
}
return
eo.
identifier;
}
/**
* Processes a request from a web browser (an ObjectImporter).
*/
public void
doReply(
InputStream in,
OutputStream out,
String cmd)
throws
IOException,
BadHttpRequest
{
if (
cmd.
startsWith("POST /rmi "))
processRMI(
in,
out);
else if (
cmd.
startsWith("POST /lookup "))
lookupName(
cmd,
in,
out);
else
super.doReply(
in,
out,
cmd);
}
private void
processRMI(
InputStream ins,
OutputStream outs)
throws
IOException
{
ObjectInputStream in = new
ObjectInputStream(
ins);
int
objectId =
in.
readInt();
int
methodId =
in.
readInt();
Exception err = null;
Object rvalue = null;
try {
ExportedObject eo
= (
ExportedObject)
exportedObjects.
elementAt(
objectId);
Object[]
args =
readParameters(
in);
rvalue =
convertRvalue(
eo.
methods[
methodId].
invoke(
eo.
object,
args));
}
catch(
Exception e) {
err =
e;
logging2(
e.
toString());
}
outs.
write(
okHeader);
ObjectOutputStream out = new
ObjectOutputStream(
outs);
if (
err != null) {
out.
writeBoolean(false);
out.
writeUTF(
err.
toString());
}
else
try {
out.
writeBoolean(true);
out.
writeObject(
rvalue);
}
catch (
NotSerializableException e) {
logging2(
e.
toString());
}
catch (
InvalidClassException e) {
logging2(
e.
toString());
}
out.
flush();
out.
close();
in.
close();
}
private
Object[]
readParameters(
ObjectInputStream in)
throws
IOException,
ClassNotFoundException
{
int
n =
in.
readInt();
Object[]
args = new
Object[
n];
for (int
i = 0;
i <
n; ++
i) {
Object a =
in.
readObject();
if (
a instanceof
RemoteRef) {
RemoteRef ref = (
RemoteRef)
a;
ExportedObject eo
= (
ExportedObject)
exportedObjects.
elementAt(
ref.
oid);
a =
eo.
object;
}
args[
i] =
a;
}
return
args;
}
private
Object convertRvalue(
Object rvalue)
throws
CannotCompileException
{
if (
rvalue == null)
return null; // the return type is void.
String classname =
rvalue.
getClass().
getName();
if (
stubGen.
isProxyClass(
classname))
return new
RemoteRef(
exportObject(null,
rvalue),
classname);
else
return
rvalue;
}
private void
lookupName(
String cmd,
InputStream ins,
OutputStream outs)
throws
IOException
{
ObjectInputStream in = new
ObjectInputStream(
ins);
String name =
DataInputStream.
readUTF(
in);
ExportedObject found = (
ExportedObject)
exportedNames.
get(
name);
outs.
write(
okHeader);
ObjectOutputStream out = new
ObjectOutputStream(
outs);
if (
found == null) {
logging2(
name + "not found.");
out.
writeInt(-1); // error code
out.
writeUTF("error");
}
else {
logging2(
name);
out.
writeInt(
found.
identifier);
out.
writeUTF(
found.
object.
getClass().
getName());
}
out.
flush();
out.
close();
in.
close();
}
}
class
ExportedObject {
public int
identifier;
public
Object object;
public
Method[]
methods;
}