ObjectInputStream.java (resolveProxyClass): New method from Classpath.

* java/io/ObjectInputStream.java (resolveProxyClass): New method
	from Classpath.
	* Makefile.in: Rebuilt.
	* Makefile.am (rmi_java_source_files): Added new files.
	* gnu/java/rmi/RMIMarshalledObjectInputStream.java,
	gnu/java/rmi/RMIMarshalledObjectOutputStream.java,
	gnu/java/rmi/server/ConnectionRunnerPool.java: New files from
	Classpath.
	* gnu/java/rmi/dgc/DGCImpl.java,
	gnu/java/rmi/dgc/DGCImpl_Skel.java,
	gnu/java/rmi/dgc/DGCImpl_Stub.java,
	gnu/java/rmi/registry/RegistryImpl_Skel.java,
	gnu/java/rmi/registry/RegistryImpl_Stub.java,
	gnu/java/rmi/server/RMIHashes.java,
	gnu/java/rmi/server/RMIObjectInputStream.java,
	gnu/java/rmi/server/RMIObjectOutputStream.java,
	gnu/java/rmi/server/UnicastConnection.java,
	gnu/java/rmi/server/UnicastConnectionManager.java,
	gnu/java/rmi/server/UnicastRef.java,
	gnu/java/rmi/server/UnicastServer.java,
	gnu/java/rmi/server/UnicastServerRef.java,
	java/rmi/MarshalledObject.java,
	java/rmi/server/RMIClassLoader.java,
	java/rmi/server/RemoteObject.java,
	java/rmi/server/UnicastRemoteObject.java,
	java/security/SecureClassLoader.java: Merged from Classpath.

From-SVN: r57675
This commit is contained in:
Tom Tromey 2002-10-01 03:46:43 +00:00 committed by Tom Tromey
parent e3e3815b7f
commit d74732f5cd
28 changed files with 1175 additions and 156 deletions

View file

@ -0,0 +1,154 @@
/* gnu.java.rmi.server.ConnectionRunnerPool
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.rmi.server;
import java.util.ArrayList;
import java.util.Arrays;
//Should I generalize this class?
class ConnectionRunnerPool
{
public static
class ConnectionRunner extends Thread{
private UnicastConnection conn;
private volatile boolean exiting = false;
public ConnectionRunner(ThreadGroup group, String id){
super(group, id);
}
public synchronized void run(){
while(!exiting){
if(conn == null)
try{
wait();
}catch(InterruptedException e){
continue;
}
else{
conn.run();
conn = null;
synchronized(ConnectionRunnerPool.class){
freelist.add(this);
if(freelist.size() == 1)
ConnectionRunnerPool.class.notifyAll();
}
}
}
}
public synchronized void dispatch(UnicastConnection conn){
this.conn = conn;
notify();
}
void exit(){
exiting = true;
if(conn != null)
try{
join(500);
}catch(InterruptedException e){}
interrupt();
}
}
private static int size = 5;
private static int max_size = 10;
private static ArrayList freelist;
private static ThreadGroup group = new ThreadGroup("pool");
static {
ConnectionRunner[] pools = new ConnectionRunner[size];
for(int i = 0; i < pools.length; i++){
pools[i] = new ConnectionRunner(group, new Integer(i).toString());
pools[i].setContextClassLoader(Thread.currentThread().getContextClassLoader());
pools[i].start();
}
freelist = new ArrayList(Arrays.asList(pools));
}
public static void setSize(int size_){
size = size_;
}
public static void setMaxSize(int size){
max_size = size;
}
private synchronized static ConnectionRunner getConnectionRunner()
{
if(freelist.size() == 0){
if(size < max_size){
++size;
ConnectionRunner a = new ConnectionRunner(group, new Integer(size).toString());
a.start();
freelist.add(a);
}else
while(freelist.size() == 0)
try{
ConnectionRunnerPool.class.wait();
}catch(InterruptedException e){}
}
// always let the first in pool most busy or other scheduling plan??
ConnectionRunner a = (ConnectionRunner)freelist.get(0);
freelist.remove(a);
return a;
}
public static void dispatchConnection(UnicastConnection conn)
{
ConnectionRunner r = getConnectionRunner();
r.dispatch(conn);
}
public static void exit()
{
Thread[] list = new Thread[group.activeCount()];
group.enumerate(list);
for(int i = 0; i < list.length; i++)
((ConnectionRunner)list[i]).exit();
}
}

View file

@ -39,13 +39,56 @@ package gnu.java.rmi.server;
import java.lang.reflect.Method;
import java.lang.Class;
import gnu.java.security.provider.SHA;
import gnu.java.io.NullOutputStream;
import gnu.java.lang.reflect.TypeSignature;
import java.security.MessageDigest;
import java.security.DigestOutputStream;
import java.io.DataOutputStream;
import java.io.ByteArrayOutputStream;
public class RMIHashes
{
//There're other places using DigestOutputStream to generate hash in classpath, but I think the way I used
//here is more efficient, anyway, you can switch to DigestOutputStream by doing like "//or:" comments say.
//or:add this statement: private static final NullOutputStream nullOutputStream = new NullOutputStream ();
public static long getMethodHash(Method meth)
{
return meth.hashCode ();
//Object Serialization Spec 8.3
try
{
MessageDigest md = MessageDigest.getInstance ("SHA");
//or:remove this statement: DigestOutputStream digest_out = new DigestOutputStream (nullOutputStream, md);
ByteArrayOutputStream digest_out = new ByteArrayOutputStream();
DataOutputStream data_out = new DataOutputStream (digest_out);
StringBuffer sbuf = new StringBuffer();
sbuf.append(meth.getName());
sbuf.append('(');
Class params[] = meth.getParameterTypes();
for(int i = 0; i < params.length; i++)
sbuf.append(TypeSignature.getEncodingOfClass(params[i]));
sbuf.append(')');
Class rcls = meth.getReturnType();
if(rcls != Void.TYPE)
sbuf.append(TypeSignature.getEncodingOfClass(rcls));
else
sbuf.append('V');
data_out.writeUTF (sbuf.toString());
data_out.flush();
data_out.close ();
md.update(digest_out.toByteArray()); //or:remove this statement
byte[] sha = md.digest ();
long result = 0;
int len = sha.length < 8 ? sha.length : 8;
for (int i=0; i < len; i++)
result += (long)(sha[i] & 0xFF) << (8 * i);
return result;
}catch(Exception _){
return -1L;
}
}
public static long getInterfaceHash(Class clazz)
@ -53,3 +96,4 @@ public class RMIHashes
return clazz.hashCode ();
}
}

View file

@ -44,6 +44,8 @@ import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;
import java.rmi.server.RMIClassLoader;
import java.lang.ClassNotFoundException;
import java.lang.reflect.Proxy;
public class RMIObjectInputStream
extends ObjectInputStream {
@ -56,20 +58,80 @@ public RMIObjectInputStream(InputStream strm, UnicastConnectionManager man) thro
enableResolveObject(true);
}
public RMIObjectInputStream(InputStream strm) throws IOException {
this(strm, UnicastConnectionManager.getInstance(0, null));
}
protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
//System.out.println("Resolving class: " + desc.getName());
String annotation = (String)readObject();
if (annotation == null) {
return (super.resolveClass(desc));
String annotation = (String)getAnnotation();
try{
return super.resolveClass(desc);
}catch(ClassNotFoundException _){};
try {
if(annotation == null)
return (RMIClassLoader.loadClass(desc.getName()));
else
return (RMIClassLoader.loadClass(annotation, desc.getName()));
}
else {
try {
return (RMIClassLoader.loadClass(new URL(annotation), desc.getName()));
}
catch (MalformedURLException _) {
throw new ClassNotFoundException(desc.getName());
}
catch (MalformedURLException _) {
throw new ClassNotFoundException(desc.getName());
}
}
//Separate it for override by MarshalledObject
protected Object getAnnotation()
throws IOException, ClassNotFoundException
{
return readObject();
}
protected Class resolveProxyClass(String intfs[])
throws IOException, ClassNotFoundException
{
String annotation = (String)getAnnotation();
try{
return super.resolveProxyClass(intfs);
}catch(ClassNotFoundException _){};
Class clss[] = new Class[intfs.length];
if(annotation == null)
clss[0] = RMIClassLoader.loadClass(intfs[0]);
else
clss[0] = RMIClassLoader.loadClass(annotation, intfs[0]);
//assume all interfaces can be loaded by the same classloader
ClassLoader loader = clss[0].getClassLoader();
if(loader == null)
for(int i = 1; i < intfs.length; i++)
clss[i] = Class.forName(intfs[i]);
else
for(int i = 1; i < intfs.length; i++)
clss[i] = loader.loadClass(intfs[i]);
return Proxy.getProxyClass(loader, clss);
}
protected Object readValue(Class valueClass) throws IOException, ClassNotFoundException {
if(valueClass.isPrimitive()){
if(valueClass == Boolean.TYPE)
return new Boolean(readBoolean());
if(valueClass == Byte.TYPE)
return new Byte(readByte());
if(valueClass == Character.TYPE)
return new Character(readChar());
if(valueClass == Short.TYPE)
return new Short(readShort());
if(valueClass == Integer.TYPE)
return new Integer(readInt());
if(valueClass == Long.TYPE)
return new Long(readLong());
if(valueClass == Float.TYPE)
return new Float(readFloat());
if(valueClass == Double.TYPE)
return new Double(readDouble());
else
throw new Error("Unsupported primitive class: " + valueClass);
} else
return readObject();
}
}

View file

@ -41,17 +41,74 @@ import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.rmi.server.RMIClassLoader;
import java.rmi.Remote;
import java.rmi.server.RemoteStub;
import java.rmi.server.ObjID;
public class RMIObjectOutputStream
extends ObjectOutputStream {
public RMIObjectOutputStream(OutputStream strm) throws IOException {
super(strm);
enableReplaceObject(true);
}
//Separate it for override by MarshalledObject
protected void setAnnotation(String annotation) throws IOException{
writeObject(annotation);
}
protected void annotateClass(Class cls) throws IOException {
//System.out.println("Annotating class: " + cls);
writeObject(RMIClassLoader.getClassAnnotation(cls));
setAnnotation(RMIClassLoader.getClassAnnotation(cls));
}
protected void annotateProxyClass(Class cls)
throws IOException
{
annotateClass(cls);
}
protected Object replaceObject(Object obj)
throws IOException
{
if((obj instanceof Remote) && !(obj instanceof RemoteStub)){
UnicastServerRef ref = new UnicastServerRef(new ObjID(), 0, null);
try{
return ref.exportObject((Remote)obj);
}catch(Exception e){}
}
return obj;
}
protected void writeValue(Object value, Class valueClass) throws IOException{
if(valueClass.isPrimitive()){
if(valueClass == Boolean.TYPE)
writeBoolean(((Boolean)value).booleanValue());
else
if(valueClass == Byte.TYPE)
writeByte(((Byte)value).byteValue());
else
if(valueClass == Character.TYPE)
writeChar(((Character)value).charValue());
else
if(valueClass == Short.TYPE)
writeShort(((Short)value).shortValue());
else
if(valueClass == Integer.TYPE)
writeInt(((Integer)value).intValue());
else
if(valueClass == Long.TYPE)
writeLong(((Long)value).longValue());
else
if(valueClass == Float.TYPE)
writeFloat(((Float)value).floatValue());
else
if(valueClass == Double.TYPE)
writeDouble(((Double)value).doubleValue());
else
throw new Error("Unsupported primitive class: " + valueClass);
} else
writeObject(value);
}
}

View file

@ -44,6 +44,8 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ObjectOutput;
import java.io.ObjectInput;
import java.io.IOException;
@ -65,9 +67,10 @@ UnicastConnection(UnicastConnectionManager man, Socket sock) {
}
void acceptConnection() throws IOException {
//System.out.println("Accepting connection on " + lport);
din = new DataInputStream(sock.getInputStream());
dout = new DataOutputStream(sock.getOutputStream());
//System.out.println("Accepting connection on " + sock);
//Use BufferedXXXStream would be more efficient
din = new DataInputStream(new BufferedInputStream(sock.getInputStream()));
dout = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream()));
int sig = din.readInt();
if (sig != PROTOCOL_HEADER) {
@ -85,6 +88,7 @@ void acceptConnection() throws IOException {
// Send my hostname and port
dout.writeUTF(manager.serverName);
dout.writeInt(manager.serverPort);
dout.flush();
// Read their hostname and port
String rhost = din.readUTF();
@ -94,15 +98,16 @@ void acceptConnection() throws IOException {
}
void makeConnection(int protocol) throws IOException {
dout = new DataOutputStream(sock.getOutputStream());
din = new DataInputStream(sock.getInputStream());
//Use BufferedXXXStream would be more efficient
din = new DataInputStream(new BufferedInputStream(sock.getInputStream()));
dout = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream()));
// Send header
dout.writeInt(PROTOCOL_HEADER);
dout.writeShort(PROTOCOL_VERSION);
dout.writeByte(protocol);
dout.flush();
dout.flush();
if (protocol != SINGLE_OP_PROTOCOL) {
// Get back ack.
int ack = din.readUnsignedByte();
@ -117,6 +122,7 @@ void makeConnection(int protocol) throws IOException {
// Send them my endpoint
dout.writeUTF(manager.serverName);
dout.writeInt(manager.serverPort);
dout.flush();
}
// Okay, ready to roll ...
}
@ -144,13 +150,15 @@ ObjectOutputStream getObjectOutputStream() throws IOException {
}
void disconnect() {
oin = null;
oout = null;
try {
sock.close();
if(oout != null)
oout.close();
}
catch (IOException _) {
}
}
oin = null;
oout = null;
din = null;
dout = null;
sock = null;

View file

@ -57,9 +57,12 @@ public class UnicastConnectionManager
implements Runnable, ProtocolConstants {
private static String localhost;
// use different maps for server/client type UnicastConnectionManager
private static Hashtable servers = new Hashtable();
private static Hashtable clients = new Hashtable();
private Thread serverThread;
// make serverThread volatile for poll
private volatile Thread serverThread;
private ServerSocket ssock;
String serverName;
int serverPort;
@ -68,7 +71,9 @@ private RMIClientSocketFactory clientFactory;
static {
try {
localhost = InetAddress.getLocalHost().getHostName();
//Use host address instead of host name to avoid name resolving issues
//localhost = InetAddress.getLocalHost().getHostName();
localhost = InetAddress.getLocalHost().getHostAddress();
}
catch (UnknownHostException _) {
localhost = "localhost";
@ -112,11 +117,16 @@ public static synchronized UnicastConnectionManager getInstance(String host, int
if (csf == null) {
csf = RMISocketFactory.getSocketFactory();
}
// change host name to host address to avoid name resolving issues
try{
host = InetAddress.getByName(host).getHostAddress();
}catch(Exception _){}
TripleKey key = new TripleKey(host, port, csf);
UnicastConnectionManager man = (UnicastConnectionManager)servers.get(key);
UnicastConnectionManager man = (UnicastConnectionManager)clients.get(key);
if (man == null) {
man = new UnicastConnectionManager(host, port, csf);
servers.put(key, man);
clients.put(key, man);
}
return (man);
}
@ -198,18 +208,34 @@ public void startServer() {
serverThread.start();
}
/**
* Stop a server on this manager
*/
public void stopServer() {
synchronized(this) {
if(serverThread != null){
serverThread = null;
try{
ssock.close();
}catch(Exception _){}
}
}
}
/**
* Server thread for connection manager.
*/
public void run() {
for (;;) {
for (;serverThread != null;) { // if serverThread==null, then exit thread
try {
//System.out.println("Waiting for connection on " + serverPort);
UnicastConnection conn = getServerConnection();
(new Thread(conn)).start();
// use a thread pool to improve performance
// (new Thread(conn)).start();
ConnectionRunnerPool.dispatchConnection(conn);
}
catch (Exception e) {
e.printStackTrace();
// e.printStackTrace();
}
}
}

View file

@ -107,6 +107,7 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu
objid.write(out);
out.writeInt(opnum);
out.writeLong(hash);
/*
if (params != null) {
for (int i = 0; i < params.length; i++) {
if (params[i] instanceof UnicastRemoteObject) {
@ -117,6 +118,11 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu
}
}
}
*/
// must handle primitive class and their wrapper classes
Class clss[] = method.getParameterTypes();
for(int i = 0; i < clss.length; i++)
((RMIObjectOutputStream)out).writeValue(params[i], clss[i]);
out.flush();
}
@ -139,12 +145,25 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu
returncode = in.readUnsignedByte();
ack = UID.read(in);
returnval = in.readObject();
//returnval = in.readObject();
Class cls = method.getReturnType();
if(cls == Void.TYPE){
returnval = null;
}else
returnval = ((RMIObjectInputStream)in).readValue(cls);
}
catch (IOException e3) {
throw new RemoteException("call return failed: ", e3);
}
/* if DGCAck is necessary
//According to RMI wire protocol, send a DGCAck
// to indicate receiving return value
dout.writeByte(MESSAGE_DGCACK);
ack.write(dout);
out.flush();
*/
manager.discardConnection(conn);
if (returncode != RETURN_ACK) {
@ -183,13 +202,16 @@ public void writeExternal(ObjectOutput out) throws IOException {
}
manager.write(out);
objid.write(out);
out.writeByte(RETURN_ACK);
// This byte is somewhat confusing when interoperating with JDK
out.writeByte(0); //RETURN_ACK);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
manager = UnicastConnectionManager.read(in);
objid = ObjID.read(in);
if (in.readByte() != RETURN_ACK) {
byte ack = in.readByte();
// This byte is somewhat confusing when interoperating with JDK
if (ack != RETURN_ACK && ack != 0/*jdk ack value*/) {
throw new IOException("no ack found");
}
}

View file

@ -65,6 +65,13 @@ public static void exportObject(UnicastServerRef obj) {
obj.manager.startServer();
}
// FIX ME: I haven't handle force parameter
public static boolean unexportObject(UnicastServerRef obj, boolean force) {
objects.remove(obj.objid);
obj.manager.stopServer();
return true;
}
private static synchronized void startDGC() {
if (dgc == null) {
try {
@ -100,10 +107,14 @@ private static void incomingMessageCall(UnicastConnection conn) throws IOExcepti
UnicastServerRef uref = (UnicastServerRef)objects.get(objid);
Object returnval;
int returncode = RETURN_ACK;
// returnval is from Method.invoke(), so we must check the return class to see
// if it's primitive type
Class returncls = null;
if (uref != null) {
try {
// Dispatch the call to it.
returnval = uref.incomingMessageCall(conn, method, hash);
returncls = uref.getMethodReturnType(method, hash);
}
catch (Exception e) {
returnval = e;
@ -121,7 +132,10 @@ private static void incomingMessageCall(UnicastConnection conn) throws IOExcepti
out.writeByte(returncode);
(new UID()).write(out);
out.writeObject(returnval);
if(returnval != null && returncls != null)
((RMIObjectOutputStream)out).writeValue(returnval, returncls);
else
out.writeObject(returnval);
out.flush();
}

View file

@ -66,14 +66,15 @@ import java.io.ObjectOutputStream;
import java.util.Hashtable;
public class UnicastServerRef
extends UnicastRef {
extends UnicastRef
implements ServerRef{ //SHOULD implement ServerRef
final static private Class[] stubprototype = new Class[] { RemoteRef.class };
Remote myself;
private Skeleton skel;
private RemoteStub stub;
private Hashtable methods;
private Hashtable methods = new Hashtable();
public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf) {
super(id);
@ -95,7 +96,7 @@ public RemoteStub exportObject(Remote obj) throws RemoteException {
skel = (Skeleton)getHelperClass(cls, "_Skel");
// Build hash of methods which may be called.
buildMethodHash(obj.getClass());
buildMethodHash(obj.getClass(), true);
// Export it.
UnicastServer.exportObject(this);
@ -104,10 +105,25 @@ public RemoteStub exportObject(Remote obj) throws RemoteException {
return (stub);
}
public RemoteStub exportObject(Remote remote, Object obj)
throws RemoteException
{
//FIX ME
return exportObject(remote);
}
public boolean unexportObject(Remote obj, boolean force) throws RemoteException {
// Remove all hashes of methods which may be called.
buildMethodHash(obj.getClass(), false);
return UnicastServer.unexportObject(this, force);
}
private Object getHelperClass(Class cls, String type) {
try {
String classname = cls.getName();
Class scls = Class.forName(classname + type);
String classname = cls.getName();
ClassLoader cl = cls.getClassLoader(); //DONT use "Class scls = Class.forName(classname + type);"
Class scls = cl.loadClass(classname + type);
if (type.equals("_Stub")) {
try {
// JDK 1.2 stubs
@ -147,8 +163,7 @@ public String getClientHost() throws ServerNotActiveException {
throw new Error("Not implemented");
}
private void buildMethodHash(Class cls) {
methods = new Hashtable();
private void buildMethodHash(Class cls, boolean build) {
Method[] meths = cls.getMethods();
for (int i = 0; i < meths.length; i++) {
/* Don't need to include any java.xxx related stuff */
@ -156,11 +171,23 @@ private void buildMethodHash(Class cls) {
continue;
}
long hash = RMIHashes.getMethodHash(meths[i]);
methods.put(new Long (hash), meths[i]);
if(build)
methods.put(new Long (hash), meths[i]);
else
methods.remove(new Long (hash));
//System.out.println("meth = " + meths[i] + ", hash = " + hash);
}
}
Class getMethodReturnType(int method, long hash) throws Exception
{
if (method == -1) {
Method meth = (Method)methods.get(new Long (hash));
return meth.getReturnType();
}else
return null;
}
public Object incomingMessageCall(UnicastConnection conn, int method, long hash) throws Exception {
//System.out.println("method = " + method + ", hash = " + hash);
// If method is -1 then this is JDK 1.2 RMI - so use the hash
@ -189,7 +216,15 @@ public Object incomingMessageCall(UnicastConnection conn, int method, long hash)
throw t;
}
}
return (meth.invoke(myself, args));
//We must reinterpret the exception thrown by meth.invoke()
//return (meth.invoke(myself, args));
Object ret = null;
try{
ret = meth.invoke(myself, args);
}catch(InvocationTargetException e){
throw (Exception)(e.getTargetException());
}
return ret;
}
// Otherwise this is JDK 1.1 style RMI - we find the skeleton
// and invoke it using the method number. We wrap up our