Commit f150fe3f by Mark Wielaard Committed by Mark Wielaard

backport: MarshalledObject.java (equals): Check hashcode first.

        Merge Orp RMI patches from Wu Gansha <gansha.wu@intel.com>
	* java/rmi/MarshalledObject.java (equals): Check hashcode first.

	* java/rmi/server/RMIClassLoader.java (MyClassLoader): Create/Use
	annotation.
	(loadClass): Take String as codebases.
	(getClassAnnotation): Use MyClassLoader annotations.
	* java/rmi/server/UnicastRemoteObject.java (UnicastRemoteObject):
	call exportObject(this).

	* gnu/java/rmi/RMIMarshalledObjectOutputStream.java
	(RMIMarshalledObjectOutputStream): set locBytesStream and locStream.
	(setAnnotation): Don't set locBytesStream and locStream.
	(replaceObject): Removed.
	(flush): Don't test locStream.
	(getLocBytes): LikeWise.
	* gnu/java/rmi/dgc/DGCImpl.java: extends UnicastServerRef.
	(leaseCache): New field.
	(dirty): Use leaseCache.
	(LeaseRecord): New inner class.
	* gnu/java/rmi/registry/RegistryImpl.java (RegistryImpl): Don't
	explicitly call exportObject().
	* gnu/java/rmi/registry/RegistryImpl_Stub.java: set useNewInvoke to
	false to communicate with Sun JDK130.
	* gnu/java/rmi/server/ConnectionRunnerPool.java: Add CPU comment.
	* gnu/java/rmi/server/RMIObjectInputStream.java
	(UnicastConnectionManager): Removed field.
	* gnu/java/rmi/server/RMIObjectOutputStream.java (replaceObject):
	Use UnicastServer.getExportedRef().
	* gnu/java/rmi/server/UnicastConnection.java (reviveTime): New field.
	(expireTime): Likewise.
	(CONNECTION_TIMEOUT): Likewise.
	(disconnect): Call sock.close().
	(isExpired): New method.
	(resetTime): Likewise.
	(run): Use do while loop and catch Exception for discardConnection().
	* gnu/java/rmi/server/UnicastConnectionManager.java: Pool connections.
	* gnu/java/rmi/server/UnicastRef.java: Lots of changes.
	* gnu/java/rmi/server/UnicastRemoteCall.java: Lots of changes.
	* gnu/java/rmi/server/UnicastServer.java (refcache): New field.
	(exportObject): Use refcache.
	(unexportObject): Likewise.
	(getExportedRef): New method.
	* gnu/java/rmi/server/UnicastServerRef.java (UnicastServerRef): New
	constructor.
	(exportObject): Save manager.serverobj.
	(getStub): New method.

From-SVN: r58900
parent 396a8043
2002-11-07 Mark Wielaard <mark@klomp.org> 2002-11-07 Mark Wielaard <mark@klomp.org>
Merge Orp RMI patches from Wu Gansha <gansha.wu@intel.com>
* java/rmi/MarshalledObject.java (equals): Check hashcode first.
* java/rmi/server/RMIClassLoader.java (MyClassLoader): Create/Use
annotation.
(loadClass): Take String as codebases.
(getClassAnnotation): Use MyClassLoader annotations.
* java/rmi/server/UnicastRemoteObject.java (UnicastRemoteObject):
call exportObject(this).
* gnu/java/rmi/RMIMarshalledObjectOutputStream.java
(RMIMarshalledObjectOutputStream): set locBytesStream and locStream.
(setAnnotation): Don't set locBytesStream and locStream.
(replaceObject): Removed.
(flush): Don't test locStream.
(getLocBytes): LikeWise.
* gnu/java/rmi/dgc/DGCImpl.java: extends UnicastServerRef.
(leaseCache): New field.
(dirty): Use leaseCache.
(LeaseRecord): New inner class.
* gnu/java/rmi/registry/RegistryImpl.java (RegistryImpl): Don't
explicitly call exportObject().
* gnu/java/rmi/registry/RegistryImpl_Stub.java: set useNewInvoke to
false to communicate with Sun JDK130.
* gnu/java/rmi/server/ConnectionRunnerPool.java: Add CPU comment.
* gnu/java/rmi/server/RMIObjectInputStream.java
(UnicastConnectionManager): Removed field.
* gnu/java/rmi/server/RMIObjectOutputStream.java (replaceObject):
Use UnicastServer.getExportedRef().
* gnu/java/rmi/server/UnicastConnection.java (reviveTime): New field.
(expireTime): Likewise.
(CONNECTION_TIMEOUT): Likewise.
(disconnect): Call sock.close().
(isExpired): New method.
(resetTime): Likewise.
(run): Use do while loop and catch Exception for discardConnection().
* gnu/java/rmi/server/UnicastConnectionManager.java: Pool connections.
* gnu/java/rmi/server/UnicastRef.java: Lots of changes.
* gnu/java/rmi/server/UnicastRemoteCall.java: Lots of changes.
* gnu/java/rmi/server/UnicastServer.java (refcache): New field.
(exportObject): Use refcache.
(unexportObject): Likewise.
(getExportedRef): New method.
* gnu/java/rmi/server/UnicastServerRef.java (UnicastServerRef): New
constructor.
(exportObject): Save manager.serverobj.
(getStub): New method.
2002-11-07 Mark Wielaard <mark@klomp.org>
* java/lang/reflect/natField.cc (getBoolean): Use getType(). * java/lang/reflect/natField.cc (getBoolean): Use getType().
(getByte): Likewise. (getByte): Likewise.
(getShort): Likewise. (getShort): Likewise.
......
...@@ -61,42 +61,22 @@ public class RMIMarshalledObjectOutputStream extends RMIObjectOutputStream ...@@ -61,42 +61,22 @@ public class RMIMarshalledObjectOutputStream extends RMIObjectOutputStream
public RMIMarshalledObjectOutputStream(OutputStream objStream) throws IOException public RMIMarshalledObjectOutputStream(OutputStream objStream) throws IOException
{ {
super(objStream); super(objStream);
locBytesStream = new ByteArrayOutputStream(256);
locStream = new ObjectOutputStream(locBytesStream);
} }
//This method overrides RMIObjectOutputStream's. //This method overrides RMIObjectOutputStream's.
protected void setAnnotation(String annotation) throws IOException{ protected void setAnnotation(String annotation) throws IOException{
synchronized(this){
if(locStream == null){
locBytesStream = new ByteArrayOutputStream();
locStream = new ObjectOutputStream(locBytesStream);
}
}
locStream.writeObject(annotation); locStream.writeObject(annotation);
} }
//This method overrides ObjectOutputStream's to replace Remote to RemoteStub
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;
}
public void flush() throws IOException { public void flush() throws IOException {
super.flush(); super.flush();
if(locStream != null) locStream.flush();
locStream.flush();
} }
public byte[] getLocBytes(){ public byte[] getLocBytes(){
if(locStream != null) return locBytesStream.toByteArray();
return locBytesStream.toByteArray();
return null;
} }
} // End of RMIMarshalledObjectOutputStream } // End of RMIMarshalledObjectOutputStream
......
/* /*
Copyright (c) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -46,24 +46,73 @@ import java.rmi.server.UnicastRemoteObject; ...@@ -46,24 +46,73 @@ import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.RMISocketFactory; import java.rmi.server.RMISocketFactory;
import gnu.java.rmi.server.UnicastServerRef; import gnu.java.rmi.server.UnicastServerRef;
import java.util.Hashtable;
/**
* I let DGCImpl to extend UnicastServerRef, but not
* UnicastRemoteObject, because UnicastRemoteObject must
* exportObject automatically.
*/
public class DGCImpl public class DGCImpl
extends UnicastRemoteObject implements DGC { extends UnicastServerRef implements DGC {
private static final long leaseValue = 600000L; private static final long LEASE_VALUE = 600000L;
// leaseCache caches a LeaseRecord associated with a vmid
private Hashtable leaseCache = new Hashtable();
public DGCImpl() throws RemoteException { public DGCImpl() throws RemoteException {
super(new UnicastServerRef(new ObjID(ObjID.DGC_ID), 0, RMISocketFactory.getSocketFactory())); super(new ObjID(ObjID.DGC_ID), 0, RMISocketFactory.getSocketFactory());
} }
public Lease dirty(ObjID[] ids, long sequenceNum, Lease lease) throws RemoteException { public Lease dirty(ObjID[] ids, long sequenceNum, Lease lease) throws RemoteException {
VMID vmid = lease.getVMID(); VMID vmid = lease.getVMID();
if (vmid == null)
vmid = new VMID();
long leaseValue = LEASE_VALUE;
//long leaseValue = lease.getValue();
lease = new Lease(vmid, leaseValue); lease = new Lease(vmid, leaseValue);
System.out.println("DGCImpl.dirty - not completely implemented"); synchronized(leaseCache){
LeaseRecord lr = (LeaseRecord)leaseCache.get(vmid);
if (lr != null)
lr.reset(leaseValue);
else{
lr = new LeaseRecord(vmid, leaseValue);
leaseCache.put(vmid, lr);
}
}
return (lease); return (lease);
} }
public void clean(ObjID[] ids, long sequenceNum, VMID vmid, boolean strong) throws RemoteException { public void clean(ObjID[] ids, long sequenceNum, VMID vmid, boolean strong) throws RemoteException {
System.out.println("DGCImpl.clean - not implemented"); // Not implemented
} }
/**
* LeaseRecord associates a vmid to expireTime.
*/
private static class LeaseRecord{
private VMID vmid;
private long expireTime;
LeaseRecord(VMID vmid, long leaseValue){
this.vmid = vmid;
reset(leaseValue);
}
// reset expireTime
void reset(long leaseValue){
long l = System.currentTimeMillis();
expireTime = l + leaseValue;
}
} boolean isExpired(){
long l = System.currentTimeMillis();
if ( l > expireTime)
return true;
return false;
}
} //End of LeaseRecord
} //End of DGCImpl
...@@ -64,7 +64,8 @@ public RegistryImpl(int port) throws RemoteException { ...@@ -64,7 +64,8 @@ public RegistryImpl(int port) throws RemoteException {
public RegistryImpl(int port, RMIClientSocketFactory cf, RMIServerSocketFactory sf) throws RemoteException { public RegistryImpl(int port, RMIClientSocketFactory cf, RMIServerSocketFactory sf) throws RemoteException {
super(new UnicastServerRef(new ObjID(ObjID.REGISTRY_ID), port, sf)); super(new UnicastServerRef(new ObjID(ObjID.REGISTRY_ID), port, sf));
((UnicastServerRef)getRef()).exportObject(this); // The following is unnecessary, because UnicastRemoteObject export itself automatically.
//((UnicastServerRef)getRef()).exportObject(this);
} }
public Remote lookup(String name) throws RemoteException, NotBoundException, AccessException { public Remote lookup(String name) throws RemoteException, NotBoundException, AccessException {
......
...@@ -67,7 +67,7 @@ public final class RegistryImpl_Stub ...@@ -67,7 +67,7 @@ public final class RegistryImpl_Stub
static { static {
try { try {
java.rmi.server.RemoteRef.class.getMethod("invoke", new java.lang.Class[] { java.rmi.Remote.class, java.lang.reflect.Method.class, java.lang.Object[].class, long.class }); java.rmi.server.RemoteRef.class.getMethod("invoke", new java.lang.Class[] { java.rmi.Remote.class, java.lang.reflect.Method.class, java.lang.Object[].class, long.class });
useNewInvoke = true; useNewInvoke = false;
$method_bind_0 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("bind", new java.lang.Class[] {java.lang.String.class, java.rmi.Remote.class}); $method_bind_0 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("bind", new java.lang.Class[] {java.lang.String.class, java.rmi.Remote.class});
$method_list_1 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("list", new java.lang.Class[] {}); $method_list_1 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("list", new java.lang.Class[] {});
$method_lookup_2 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("lookup", new java.lang.Class[] {java.lang.String.class}); $method_lookup_2 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("lookup", new java.lang.Class[] {java.lang.String.class});
......
...@@ -91,6 +91,7 @@ class ConnectionRunnerPool ...@@ -91,6 +91,7 @@ class ConnectionRunnerPool
} }
// Should this value equal to number of CPU?
private static int size = 5; private static int size = 5;
private static int max_size = 10; private static int max_size = 10;
......
/* /*
Copyright (c) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -50,23 +50,13 @@ import java.lang.reflect.Proxy; ...@@ -50,23 +50,13 @@ import java.lang.reflect.Proxy;
public class RMIObjectInputStream public class RMIObjectInputStream
extends ObjectInputStream { extends ObjectInputStream {
UnicastConnectionManager manager; public RMIObjectInputStream(InputStream strm) throws IOException {
public RMIObjectInputStream(InputStream strm, UnicastConnectionManager man) throws IOException {
super(strm); super(strm);
manager = man;
enableResolveObject(true); enableResolveObject(true);
} }
public RMIObjectInputStream(InputStream strm) throws IOException {
this(strm, UnicastConnectionManager.getInstance(0, null));
}
protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
String annotation = (String)getAnnotation(); String annotation = (String)getAnnotation();
try{
return super.resolveClass(desc);
}catch(ClassNotFoundException _){};
try { try {
if(annotation == null) if(annotation == null)
...@@ -90,24 +80,23 @@ protected Class resolveProxyClass(String intfs[]) ...@@ -90,24 +80,23 @@ protected Class resolveProxyClass(String intfs[])
throws IOException, ClassNotFoundException throws IOException, ClassNotFoundException
{ {
String annotation = (String)getAnnotation(); String annotation = (String)getAnnotation();
try{
return super.resolveProxyClass(intfs);
}catch(ClassNotFoundException _){};
Class clss[] = new Class[intfs.length]; Class clss[] = new Class[intfs.length];
if(annotation == null) if(annotation == null)
clss[0] = RMIClassLoader.loadClass(intfs[0]); clss[0] = RMIClassLoader.loadClass(intfs[0]);
else else
clss[0] = RMIClassLoader.loadClass(annotation, intfs[0]); clss[0] = RMIClassLoader.loadClass(annotation, intfs[0]);
//assume all interfaces can be loaded by the same classloader //assume all interfaces can be loaded by the same classloader
ClassLoader loader = clss[0].getClassLoader(); ClassLoader loader = clss[0].getClassLoader();
if(loader == null) for (int i = 0; i < intfs.length; i++)
for(int i = 1; i < intfs.length; i++) clss[i] = Class.forName(intfs[i], false, loader);
clss[i] = Class.forName(intfs[i]);
else try {
for(int i = 1; i < intfs.length; i++)
clss[i] = loader.loadClass(intfs[i]);
return Proxy.getProxyClass(loader, clss); return Proxy.getProxyClass(loader, clss);
} catch (IllegalArgumentException e) {
throw new ClassNotFoundException(null, e);
}
} }
protected Object readValue(Class valueClass) throws IOException, ClassNotFoundException { protected Object readValue(Class valueClass) throws IOException, ClassNotFoundException {
...@@ -134,4 +123,4 @@ protected Object readValue(Class valueClass) throws IOException, ClassNotFoundEx ...@@ -134,4 +123,4 @@ protected Object readValue(Class valueClass) throws IOException, ClassNotFoundEx
return readObject(); return readObject();
} }
} }
\ No newline at end of file
/* /*
Copyright (c) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -72,10 +72,9 @@ protected Object replaceObject(Object obj) ...@@ -72,10 +72,9 @@ protected Object replaceObject(Object obj)
throws IOException throws IOException
{ {
if((obj instanceof Remote) && !(obj instanceof RemoteStub)){ if((obj instanceof Remote) && !(obj instanceof RemoteStub)){
UnicastServerRef ref = new UnicastServerRef(new ObjID(), 0, null); UnicastServerRef ref = UnicastServer.getExportedRef((Remote)obj);
try{ if (ref != null)
return ref.exportObject((Remote)obj); return ref.getStub();
}catch(Exception e){}
} }
return obj; return obj;
} }
......
/* /*
Copyright (c) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -61,6 +61,10 @@ DataOutputStream dout; ...@@ -61,6 +61,10 @@ DataOutputStream dout;
ObjectInputStream oin; ObjectInputStream oin;
ObjectOutputStream oout; ObjectOutputStream oout;
// reviveTime and expireTime make UnicastConnection pool-able
long reviveTime = 0;
long expireTime = Long.MAX_VALUE;
UnicastConnection(UnicastConnectionManager man, Socket sock) { UnicastConnection(UnicastConnectionManager man, Socket sock) {
this.manager = man; this.manager = man;
this.sock = sock; this.sock = sock;
...@@ -137,7 +141,7 @@ DataOutputStream getDataOutputStream() throws IOException { ...@@ -137,7 +141,7 @@ DataOutputStream getDataOutputStream() throws IOException {
ObjectInputStream getObjectInputStream() throws IOException { ObjectInputStream getObjectInputStream() throws IOException {
if (oin == null) { if (oin == null) {
oin = new RMIObjectInputStream(din, manager); oin = new RMIObjectInputStream(din);
} }
return (oin); return (oin);
} }
...@@ -153,6 +157,7 @@ void disconnect() { ...@@ -153,6 +157,7 @@ void disconnect() {
try { try {
if(oout != null) if(oout != null)
oout.close(); oout.close();
sock.close();
} }
catch (IOException _) { catch (IOException _) {
} }
...@@ -164,17 +169,35 @@ void disconnect() { ...@@ -164,17 +169,35 @@ void disconnect() {
sock = null; sock = null;
} }
public static final long CONNECTION_TIMEOUT = 10000L;
static boolean isExpired(UnicastConnection conn, long l){
if (l <= conn.expireTime )
return false;
return true;
}
static void resetTime(UnicastConnection conn){
long l = System.currentTimeMillis();
conn.reviveTime = l;
conn.expireTime = l + CONNECTION_TIMEOUT;
}
/** /**
* We run connects on the server. Dispatch it then discard it. * We run connects on the server. Dispatch it then discard it.
*/ */
public void run() { public void run() {
do{
try { try {
UnicastServer.dispatch(this); UnicastServer.dispatch(this);
//don't discardConnection explicitly, only when
// exception happens or the connection's expireTime
// comes
} catch (Exception e ){
manager.discardConnection(this); manager.discardConnection(this);
break;
} }
catch (Exception e) { }while(true);
e.printStackTrace();
}
} }
} }
/* /*
Copyright (c) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -41,18 +41,25 @@ import java.rmi.server.RMISocketFactory; ...@@ -41,18 +41,25 @@ import java.rmi.server.RMISocketFactory;
import java.rmi.server.RMIServerSocketFactory; import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.RMIClientSocketFactory; import java.rmi.server.RMIClientSocketFactory;
import java.rmi.RemoteException; import java.rmi.RemoteException;
import gnu.java.rmi.server.UnicastConnection;
import java.util.Hashtable;
import java.net.Socket;
import java.net.ServerSocket;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.DataInputStream;
import java.lang.Thread; import java.lang.Thread;
import java.lang.Runnable; import java.lang.Runnable;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Socket;
import java.net.ServerSocket;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import gnu.java.rmi.server.UnicastConnection;
public class UnicastConnectionManager public class UnicastConnectionManager
implements Runnable, ProtocolConstants { implements Runnable, ProtocolConstants {
...@@ -60,15 +67,33 @@ private static String localhost; ...@@ -60,15 +67,33 @@ private static String localhost;
// use different maps for server/client type UnicastConnectionManager // use different maps for server/client type UnicastConnectionManager
private static Hashtable servers = new Hashtable(); private static Hashtable servers = new Hashtable();
private static Hashtable clients = new Hashtable(); private static Hashtable clients = new Hashtable();
private ArrayList connections; //client connection pool
// make serverThread volatile for poll // make serverThread volatile for poll
private volatile Thread serverThread; private volatile Thread serverThread;
private ServerSocket ssock; private ServerSocket ssock;
String serverName; String serverName;
int serverPort; int serverPort;
static private Thread scavenger;
// If client and server are in the same VM, serverobj represents server
Object serverobj;
private static RMISocketFactory defaultSocketFactory = RMISocketFactory.getSocketFactory();
private RMIServerSocketFactory serverFactory; private RMIServerSocketFactory serverFactory;
private RMIClientSocketFactory clientFactory; private RMIClientSocketFactory clientFactory;
// The following is for debug
private static int ncsock = 0; //count of client socket
private static int nssock = 0; //count of server socket
private static int ncmanager = 0; //count of client manager
private static int nsmanager = 0; //count of server manager
private static final boolean debug = false;
private static final Object GLOBAL_LOCK = new Object();
static { static {
try { try {
//Use host address instead of host name to avoid name resolving issues //Use host address instead of host name to avoid name resolving issues
...@@ -78,16 +103,73 @@ static { ...@@ -78,16 +103,73 @@ static {
catch (UnknownHostException _) { catch (UnknownHostException _) {
localhost = "localhost"; localhost = "localhost";
} }
}
//Only one scavenger thread running globally
private static void startScavenger(){
scavenger = new Thread(new Runnable(){
public void run(){
if (debug) System.out.println("************* start scavenger.");
boolean liveon = true;
while (liveon){
// Sleep for the expire timeout
try{
Thread.sleep(UnicastConnection.CONNECTION_TIMEOUT);
}catch(InterruptedException _ie){
break;
}
liveon = false;
// Scavenge all clients' connections that're expired
Iterator iter = clients.values().iterator();
long l = System.currentTimeMillis();
try{
while(iter.hasNext()){
UnicastConnectionManager man = (UnicastConnectionManager)iter.next();
ArrayList conns = man.connections;
synchronized(conns) { // is the lock a little coarser?
for (int last = conns.size() - 1;
last >= 0;
--last)
{
UnicastConnection conn = (UnicastConnection)conns.get(last);
if (UnicastConnection.isExpired(conn, l)){
conns.remove(last);
conn.disconnect();
conn = null;
}else
liveon = true; //there're still live connections
}
}
}
}catch(ConcurrentModificationException cme) {
// handle it lazily
liveon = true;
}
}
scavenger = null;
if (debug) System.out.println("************* exit scavenger.");
}
});
scavenger.start();
} }
/**
* Client UnicastConnectionManager constructor
*/
private UnicastConnectionManager(String host, int port, RMIClientSocketFactory csf) { private UnicastConnectionManager(String host, int port, RMIClientSocketFactory csf) {
ssock = null; ssock = null;
serverName = host; serverName = host;
serverPort = port; serverPort = port;
serverFactory = null; serverFactory = null;
clientFactory = csf; clientFactory = csf;
connections = new ArrayList();
} }
/**
* Server UnicastConnectionManager constructor
*/
private UnicastConnectionManager(int port, RMIServerSocketFactory ssf) { private UnicastConnectionManager(int port, RMIServerSocketFactory ssf) {
try { try {
ssock = ssf.createServerSocket(port); ssock = ssf.createServerSocket(port);
...@@ -115,7 +197,7 @@ private UnicastConnectionManager(int port, RMIServerSocketFactory ssf) { ...@@ -115,7 +197,7 @@ private UnicastConnectionManager(int port, RMIServerSocketFactory ssf) {
public static synchronized UnicastConnectionManager getInstance(String host, int port, RMIClientSocketFactory csf) { public static synchronized UnicastConnectionManager getInstance(String host, int port, RMIClientSocketFactory csf) {
//System.out.println("getInstance: " + host + "," + port + "," + csf); //System.out.println("getInstance: " + host + "," + port + "," + csf);
if (csf == null) { if (csf == null) {
csf = RMISocketFactory.getSocketFactory(); csf = defaultSocketFactory;
} }
// change host name to host address to avoid name resolving issues // change host name to host address to avoid name resolving issues
try{ try{
...@@ -126,7 +208,17 @@ public static synchronized UnicastConnectionManager getInstance(String host, int ...@@ -126,7 +208,17 @@ public static synchronized UnicastConnectionManager getInstance(String host, int
UnicastConnectionManager man = (UnicastConnectionManager)clients.get(key); UnicastConnectionManager man = (UnicastConnectionManager)clients.get(key);
if (man == null) { if (man == null) {
man = new UnicastConnectionManager(host, port, csf); man = new UnicastConnectionManager(host, port, csf);
if (debug) {
ncmanager++;
System.out.println("\n\n ====== " + ncmanager + " client managers.\n\n");
}
clients.put(key, man); clients.put(key, man);
// Detect if client and server are in the same VM, i.e., their keys are equal
UnicastConnectionManager svrman = (UnicastConnectionManager)servers.get(key);
if(svrman != null){ // server and client are in the same VM
man.serverobj = svrman.serverobj;
}
} }
return (man); return (man);
} }
...@@ -138,12 +230,16 @@ public static synchronized UnicastConnectionManager getInstance(String host, int ...@@ -138,12 +230,16 @@ public static synchronized UnicastConnectionManager getInstance(String host, int
public static synchronized UnicastConnectionManager getInstance(int port, RMIServerSocketFactory ssf) { public static synchronized UnicastConnectionManager getInstance(int port, RMIServerSocketFactory ssf) {
//System.out.println("getInstance: " + port + "," + ssf); //System.out.println("getInstance: " + port + "," + ssf);
if (ssf == null) { if (ssf == null) {
ssf = RMISocketFactory.getSocketFactory(); ssf = defaultSocketFactory;
} }
TripleKey key = new TripleKey(localhost, port, ssf); TripleKey key = new TripleKey(localhost, port, ssf);
UnicastConnectionManager man = (UnicastConnectionManager)servers.get(key); UnicastConnectionManager man = (UnicastConnectionManager)servers.get(key);
if (man == null) { if (man == null) {
man = new UnicastConnectionManager(port, ssf); man = new UnicastConnectionManager(port, ssf);
if (debug) {
nsmanager++;
System.out.println("\n\n ****** " + nsmanager + " server managers.\n\n");
}
// The provided port might not be the set port. // The provided port might not be the set port.
key.port = man.serverPort; key.port = man.serverPort;
servers.put(key, man); servers.put(key, man);
...@@ -168,9 +264,14 @@ public UnicastConnection getConnection() throws IOException { ...@@ -168,9 +264,14 @@ public UnicastConnection getConnection() throws IOException {
*/ */
private UnicastConnection getServerConnection() throws IOException { private UnicastConnection getServerConnection() throws IOException {
Socket sock = ssock.accept(); Socket sock = ssock.accept();
sock.setTcpNoDelay(true); //??
UnicastConnection conn = new UnicastConnection(this, sock); UnicastConnection conn = new UnicastConnection(this, sock);
conn.acceptConnection(); conn.acceptConnection();
//System.out.println("Server connection " + conn); if (debug){
nssock++;
System.out.println("\n\n ****** " + nssock + " server socks.\n\n");
}
//System.out.println("Server connection " + sock);
return (conn); return (conn);
} }
...@@ -178,10 +279,38 @@ private UnicastConnection getServerConnection() throws IOException { ...@@ -178,10 +279,38 @@ private UnicastConnection getServerConnection() throws IOException {
* Make a conection from this client to the server. * Make a conection from this client to the server.
*/ */
private UnicastConnection getClientConnection() throws IOException { private UnicastConnection getClientConnection() throws IOException {
ArrayList conns = connections;
UnicastConnection conn;
synchronized(conns) {
int nconn = conns.size() - 1;
// if there're free connections in connection pool
if(nconn >= 0) {
conn = (UnicastConnection)conns.get(nconn);
//Should we check if conn is alive using Ping??
conns.remove(nconn);
// Check if the connection is already expired
long l = System.currentTimeMillis();
if (!UnicastConnection.isExpired(conn, l)){
return conn;
}else {
conn.disconnect();
conn = null;
}
}
}
Socket sock = clientFactory.createSocket(serverName, serverPort); Socket sock = clientFactory.createSocket(serverName, serverPort);
UnicastConnection conn = new UnicastConnection(this, sock); conn = new UnicastConnection(this, sock);
conn.makeConnection(DEFAULT_PROTOCOL); conn.makeConnection(DEFAULT_PROTOCOL);
//System.out.println("Client connection " + conn);
if (debug) {
ncsock++;
System.out.println("\n\n ====== " + ncsock + " client socks.\n\n");
}
return (conn); return (conn);
} }
...@@ -191,7 +320,19 @@ private UnicastConnection getClientConnection() throws IOException { ...@@ -191,7 +320,19 @@ private UnicastConnection getClientConnection() throws IOException {
*/ */
public void discardConnection(UnicastConnection conn) { public void discardConnection(UnicastConnection conn) {
//System.out.println("Discarding connection " + conn); //System.out.println("Discarding connection " + conn);
//conn.disconnect();
if (ssock != null) //server connection
conn.disconnect(); conn.disconnect();
else {
// To client connection, we'd like to return back to pool
UnicastConnection.resetTime(conn);
//Ensure there're only one scavenger globally
synchronized(GLOBAL_LOCK) {
connections.add(conn); //borrow this lock to garantee thread safety
if (scavenger == null)
startScavenger();
}
}
} }
/** /**
...@@ -204,6 +345,8 @@ public void startServer() { ...@@ -204,6 +345,8 @@ public void startServer() {
return; return;
} }
serverThread = new Thread(this); serverThread = new Thread(this);
// The following is not necessary when java.lang.Thread's constructor do this.
// serverThread.setContextClassLoader(Thread.currentThread().getContextClassLoader());
} }
serverThread.start(); serverThread.start();
} }
...@@ -231,11 +374,11 @@ public void run() { ...@@ -231,11 +374,11 @@ public void run() {
//System.out.println("Waiting for connection on " + serverPort); //System.out.println("Waiting for connection on " + serverPort);
UnicastConnection conn = getServerConnection(); UnicastConnection conn = getServerConnection();
// use a thread pool to improve performance // use a thread pool to improve performance
// (new Thread(conn)).start(); //ConnectionRunnerPool.dispatchConnection(conn);
ConnectionRunnerPool.dispatchConnection(conn); (new Thread(conn)).start();
} }
catch (Exception e) { catch (Exception e) {
// e.printStackTrace(); e.printStackTrace();
} }
} }
} }
...@@ -254,8 +397,9 @@ void write(ObjectOutput out) throws IOException { ...@@ -254,8 +397,9 @@ void write(ObjectOutput out) throws IOException {
static UnicastConnectionManager read(ObjectInput in) throws IOException { static UnicastConnectionManager read(ObjectInput in) throws IOException {
String host = in.readUTF(); String host = in.readUTF();
int port = in.readInt(); int port = in.readInt();
RMIClientSocketFactory csf = ((RMIObjectInputStream)in).manager.clientFactory; //RMIClientSocketFactory csf = ((RMIObjectInputStream)in).manager.clientFactory;
return (getInstance(host, port, csf)); //return (getInstance(host, port, csf));
return (getInstance(host, port, null));
} }
} }
...@@ -288,7 +432,7 @@ public boolean equals(Object obj) { ...@@ -288,7 +432,7 @@ public boolean equals(Object obj) {
TripleKey other = (TripleKey)obj; TripleKey other = (TripleKey)obj;
if (this.host.equals(other.host) && if (this.host.equals(other.host) &&
this.other == other.other && this.other == other.other &&
(this.port == other.port || this.port == 0 || other.port == 0)) { (this.port == other.port /* || this.port == 0 || other.port == 0*/)) {
return (true); return (true);
} }
} }
......
/* /*
Copyright (c) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -62,6 +62,8 @@ import java.io.ObjectOutputStream; ...@@ -62,6 +62,8 @@ import java.io.ObjectOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.lang.reflect.InvocationTargetException;
public class UnicastRef public class UnicastRef
implements RemoteRef, ProtocolConstants { implements RemoteRef, ProtocolConstants {
...@@ -69,9 +71,10 @@ public ObjID objid; ...@@ -69,9 +71,10 @@ public ObjID objid;
UnicastConnectionManager manager; UnicastConnectionManager manager;
/** /**
* Used by serialization. * Used by serialization, and let subclass capable of having default constructor
*/ */
private UnicastRef() { //private
UnicastRef() {
} }
public UnicastRef(ObjID objid, String host, int port, RMIClientSocketFactory csf) { public UnicastRef(ObjID objid, String host, int port, RMIClientSocketFactory csf) {
...@@ -84,6 +87,21 @@ public UnicastRef(ObjID objid) { ...@@ -84,6 +87,21 @@ public UnicastRef(ObjID objid) {
} }
public Object invoke(Remote obj, Method method, Object[] params, long opnum) throws Exception { public Object invoke(Remote obj, Method method, Object[] params, long opnum) throws Exception {
// Check if client and server are in the same VM, then local call can be used to
// replace remote call, but it's somewhat violating remote semantic.
Object svrobj = manager.serverobj;
if(svrobj != null){
//local call
Object ret = null;
try{
ret = method.invoke(svrobj, params);
}catch(InvocationTargetException e){
throw (Exception)e.getTargetException();
}
//System.out.println("\n\n ***** local call: " + method + "\nreturn: " + ret + "\n\n");
return ret;
}
//System.out.println("***************** remote call:" + manager.serverPort);
return (invokeCommon(obj, method, params, -1, opnum)); return (invokeCommon(obj, method, params, -1, opnum));
} }
...@@ -107,18 +125,7 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu ...@@ -107,18 +125,7 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu
objid.write(out); objid.write(out);
out.writeInt(opnum); out.writeInt(opnum);
out.writeLong(hash); out.writeLong(hash);
/*
if (params != null) {
for (int i = 0; i < params.length; i++) {
if (params[i] instanceof UnicastRemoteObject) {
out.writeObject(UnicastRemoteObject.exportObject((UnicastRemoteObject)params[i]));
}
else {
out.writeObject(params[i]);
}
}
}
*/
// must handle primitive class and their wrapper classes // must handle primitive class and their wrapper classes
Class clss[] = method.getParameterTypes(); Class clss[] = method.getParameterTypes();
for(int i = 0; i < clss.length; i++) for(int i = 0; i < clss.length; i++)
...@@ -137,26 +144,30 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu ...@@ -137,26 +144,30 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu
UID ack; UID ack;
try { try {
din = conn.getDataInputStream(); din = conn.getDataInputStream();
if (din.readUnsignedByte() != MESSAGE_CALL_ACK) {
throw new RemoteException("Call not acked"); if ((returncode = din.readUnsignedByte()) != MESSAGE_CALL_ACK) {
conn.disconnect();
throw new RemoteException("Call not acked:" + returncode);
} }
in = conn.getObjectInputStream(); in = conn.getObjectInputStream();
returncode = in.readUnsignedByte(); returncode = in.readUnsignedByte();
ack = UID.read(in); ack = UID.read(in);
//returnval = in.readObject();
Class cls = method.getReturnType(); Class cls = method.getReturnType();
if(cls == Void.TYPE){ if(cls == Void.TYPE){
returnval = null; returnval = null;
in.readObject();
}else }else
returnval = ((RMIObjectInputStream)in).readValue(cls); returnval = ((RMIObjectInputStream)in).readValue(cls);
} }
catch (IOException e3) { catch (IOException e3) {
//for debug: e3.printStackTrace();
throw new RemoteException("call return failed: ", e3); throw new RemoteException("call return failed: ", e3);
} }
/* if DGCAck is necessary /* if DGCAck is necessary??
//According to RMI wire protocol, send a DGCAck //According to RMI wire protocol, send a DGCAck
// to indicate receiving return value // to indicate receiving return value
dout.writeByte(MESSAGE_DGCACK); dout.writeByte(MESSAGE_DGCACK);
...@@ -166,7 +177,7 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu ...@@ -166,7 +177,7 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu
manager.discardConnection(conn); manager.discardConnection(conn);
if (returncode != RETURN_ACK) { if (returncode != RETURN_ACK && returnval != null) {
throw (Exception)returnval; throw (Exception)returnval;
} }
...@@ -177,7 +188,18 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu ...@@ -177,7 +188,18 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu
* @deprecated * @deprecated
*/ */
public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum, long hash) throws RemoteException { public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum, long hash) throws RemoteException {
return (new UnicastRemoteCall(obj, opnum, hash)); UnicastConnection conn;
try {
conn = manager.getConnection();
}
catch (IOException e1) {
throw new RemoteException("connection failed to host: " + manager.serverName, e1);
}
//obj: useless?
return (new UnicastRemoteCall(conn, objid, opnum, hash));
} }
/** /**
...@@ -185,15 +207,19 @@ public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum, long hash ...@@ -185,15 +207,19 @@ public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum, long hash
*/ */
public void invoke(RemoteCall call) throws Exception { public void invoke(RemoteCall call) throws Exception {
UnicastRemoteCall c = (UnicastRemoteCall)call; UnicastRemoteCall c = (UnicastRemoteCall)call;
Object ret = invokeCommon((Remote)c.getObject(), (Method)null, c.getArguments(), c.getOpnum(), c.getHash()); call.executeCall();
c.setReturnValue(ret);
} }
/** /**
* @deprecated * @deprecated
*/ */
public void done(RemoteCall call) throws RemoteException { public void done(RemoteCall call) throws RemoteException {
/* Does nothing */ UnicastRemoteCall c = (UnicastRemoteCall)call;
try{
c.done();
} catch(IOException e){}
UnicastConnection conn = c.getConnection();
manager.discardConnection(conn);
} }
public void writeExternal(ObjectOutput out) throws IOException { public void writeExternal(ObjectOutput out) throws IOException {
......
...@@ -38,14 +38,24 @@ exception statement from your version. */ ...@@ -38,14 +38,24 @@ exception statement from your version. */
package gnu.java.rmi.server; package gnu.java.rmi.server;
import java.lang.Exception; import java.lang.Exception;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.StreamCorruptedException; import java.io.StreamCorruptedException;
import java.rmi.server.RemoteCall; import java.rmi.server.RemoteCall;
import java.rmi.RemoteException;
import java.rmi.MarshalException;
import java.rmi.UnmarshalException;
import java.rmi.server.UID;
import java.rmi.server.ObjID;
import java.rmi.server.RemoteObject;
import java.util.Vector; import java.util.Vector;
public class UnicastRemoteCall implements RemoteCall public class UnicastRemoteCall
implements RemoteCall, ProtocolConstants
{ {
private UnicastConnection conn; private UnicastConnection conn;
...@@ -56,6 +66,9 @@ public class UnicastRemoteCall implements RemoteCall ...@@ -56,6 +66,9 @@ public class UnicastRemoteCall implements RemoteCall
private Vector vec; private Vector vec;
private int ptr; private int ptr;
private ObjectOutput oout;
private ObjectInput oin;
/** /**
* Incoming call. * Incoming call.
*/ */
...@@ -67,30 +80,71 @@ public class UnicastRemoteCall implements RemoteCall ...@@ -67,30 +80,71 @@ public class UnicastRemoteCall implements RemoteCall
/** /**
* Outgoing call. * Outgoing call.
*/ */
UnicastRemoteCall(Object obj, int opnum, long hash) UnicastRemoteCall(UnicastConnection conn, ObjID objid, int opnum, long hash)
throws RemoteException
{ {
this.object = obj; this.conn = conn;
this.opnum = opnum; this.opnum = opnum;
this.hash = hash; this.hash = hash;
// signal the call when constructing
try
{
DataOutputStream dout = conn.getDataOutputStream();
dout.write(MESSAGE_CALL);
oout = conn.getObjectOutputStream();
objid.write(oout);
oout.writeInt(opnum);
oout.writeLong(hash);
}
catch(IOException ex)
{
throw new MarshalException("Try to write header but failed.", ex);
}
} }
UnicastConnection getConnection()
{
return conn;
}
public ObjectOutput getOutputStream() throws IOException public ObjectOutput getOutputStream() throws IOException
{ {
vec = new Vector(); if (conn != null)
return new DummyObjectOutputStream(); {
if(oout == null)
return (oout = conn.getObjectOutputStream());
else
return oout;
}
else
{
vec = new Vector();
return (new DummyObjectOutputStream());
}
} }
public void releaseOutputStream() throws IOException public void releaseOutputStream() throws IOException
{ {
// Does nothing. if(oout != null)
oout.flush();
} }
public ObjectInput getInputStream() throws IOException public ObjectInput getInputStream() throws IOException
{ {
if (conn != null) if (conn != null)
return conn.getObjectInputStream(); {
ptr = 0; if(oin == null)
return new DummyObjectInputStream(); return (oin = conn.getObjectInputStream());
else
return oin;
}
else
{
ptr = 0;
return (new DummyObjectInputStream());
}
} }
public void releaseInputStream() throws IOException public void releaseInputStream() throws IOException
...@@ -104,15 +158,57 @@ public class UnicastRemoteCall implements RemoteCall ...@@ -104,15 +158,57 @@ public class UnicastRemoteCall implements RemoteCall
vec = new Vector(); vec = new Vector();
return new DummyObjectOutputStream(); return new DummyObjectOutputStream();
} }
public void executeCall() throws Exception public void executeCall() throws Exception
{ {
throw new Error("Not implemented"); byte returncode;
ObjectInput oin;
try
{
releaseOutputStream();
DataInputStream din = conn.getDataInputStream();
if (din.readByte() != MESSAGE_CALL_ACK)
throw new RemoteException("Call not acked");
oin = getInputStream();
returncode = oin.readByte();
UID.read(oin);
}
catch(IOException ex)
{
throw new UnmarshalException("Try to read header but failed:", ex);
}
//check return code
switch(returncode)
{
case RETURN_ACK: //it's ok
return;
case RETURN_NACK:
Object returnobj;
try
{
returnobj = oin.readObject();
}
catch(Exception ex2)
{
throw new UnmarshalException
("Try to read exception object but failed", ex2);
}
if(!(returnobj instanceof Exception))
throw new UnmarshalException("Should be Exception type here: "
+ returnobj);
throw (Exception)returnobj;
default:
throw new UnmarshalException("Invalid return code");
}
} }
public void done() throws IOException public void done() throws IOException
{ {
/* Does nothing */ // conn.disconnect();
} }
Object returnValue() Object returnValue()
......
/* /*
Copyright (c) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -45,6 +45,7 @@ import java.io.IOException; ...@@ -45,6 +45,7 @@ import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.Hashtable; import java.util.Hashtable;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.rmi.Remote;
import java.rmi.server.ObjID; import java.rmi.server.ObjID;
import java.rmi.server.UnicastRemoteObject; import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.UID; import java.rmi.server.UID;
...@@ -56,27 +57,36 @@ import gnu.java.rmi.dgc.DGCImpl; ...@@ -56,27 +57,36 @@ import gnu.java.rmi.dgc.DGCImpl;
public class UnicastServer public class UnicastServer
implements ProtocolConstants { implements ProtocolConstants {
static private Hashtable objects = new Hashtable(); static private Hashtable objects = new Hashtable(); //mapping OBJID to server ref
static private Hashtable refcache = new Hashtable(); //mapping obj itself to server ref
static private DGCImpl dgc; static private DGCImpl dgc;
public static void exportObject(UnicastServerRef obj) { public static void exportObject(UnicastServerRef obj) {
startDGC(); startDGC();
objects.put(obj.objid, obj); objects.put(obj.objid, obj);
refcache.put(obj.myself, obj);
obj.manager.startServer(); obj.manager.startServer();
} }
// FIX ME: I haven't handle force parameter // FIX ME: I haven't handle force parameter
public static boolean unexportObject(UnicastServerRef obj, boolean force) { public static boolean unexportObject(UnicastServerRef obj, boolean force) {
objects.remove(obj.objid); objects.remove(obj.objid);
refcache.remove(obj.myself);
obj.manager.stopServer(); obj.manager.stopServer();
return true; return true;
} }
public static UnicastServerRef getExportedRef(Remote remote){
return (UnicastServerRef)refcache.get(remote);
}
private static synchronized void startDGC() { private static synchronized void startDGC() {
if (dgc == null) { if (dgc == null) {
try { try {
dgc = new DGCImpl(); dgc = new DGCImpl();
((UnicastServerRef)dgc.getRef()).exportObject(dgc); // Changed DGCImpl to inherit UnicastServerRef directly
//((UnicastServerRef)dgc.getRef()).exportObject(dgc);
dgc.exportObject(dgc);
} }
catch (RemoteException e) { catch (RemoteException e) {
e.printStackTrace(); e.printStackTrace();
......
/* /*
Copyright (c) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -63,6 +63,8 @@ import java.io.DataInputStream; ...@@ -63,6 +63,8 @@ import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Hashtable; import java.util.Hashtable;
public class UnicastServerRef public class UnicastServerRef
...@@ -71,11 +73,18 @@ public class UnicastServerRef ...@@ -71,11 +73,18 @@ public class UnicastServerRef
final static private Class[] stubprototype = new Class[] { RemoteRef.class }; final static private Class[] stubprototype = new Class[] { RemoteRef.class };
Remote myself; Remote myself; //save the remote object itself
private Skeleton skel; private Skeleton skel;
private RemoteStub stub; private RemoteStub stub;
private Hashtable methods = new Hashtable(); private Hashtable methods = new Hashtable();
/**
* Used by serialization.
*/
UnicastServerRef()
{
}
public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf) { public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf) {
super(id); super(id);
manager = UnicastConnectionManager.getInstance(port, ssf); manager = UnicastConnectionManager.getInstance(port, ssf);
...@@ -84,6 +93,9 @@ public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf) { ...@@ -84,6 +93,9 @@ public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf) {
public RemoteStub exportObject(Remote obj) throws RemoteException { public RemoteStub exportObject(Remote obj) throws RemoteException {
if (myself == null) { if (myself == null) {
myself = obj; myself = obj;
// Save it to server manager, to let client calls in the same VM to issue
// local call
manager.serverobj = obj;
// Find and install the stub // Find and install the stub
Class cls = obj.getClass(); Class cls = obj.getClass();
...@@ -112,6 +124,10 @@ public RemoteStub exportObject(Remote remote, Object obj) ...@@ -112,6 +124,10 @@ public RemoteStub exportObject(Remote remote, Object obj)
return exportObject(remote); return exportObject(remote);
} }
public RemoteStub getStub(){
return stub;
}
public boolean unexportObject(Remote obj, boolean force) throws RemoteException { public boolean unexportObject(Remote obj, boolean force) throws RemoteException {
// Remove all hashes of methods which may be called. // Remove all hashes of methods which may be called.
......
...@@ -78,6 +78,10 @@ public final class MarshalledObject ...@@ -78,6 +78,10 @@ public final class MarshalledObject
{ {
if(obj == null || !(obj instanceof MarshalledObject) ) if(obj == null || !(obj instanceof MarshalledObject) )
return false; return false;
// hashCode even differs, don't do the time-consuming comparisons
if (obj.hashCode() != hash)
return false;
MarshalledObject aobj = (MarshalledObject)obj; MarshalledObject aobj = (MarshalledObject)obj;
if (objBytes == null || aobj.objBytes == null) if (objBytes == null || aobj.objBytes == null)
......
...@@ -43,39 +43,72 @@ import java.net.URLClassLoader; ...@@ -43,39 +43,72 @@ import java.net.URLClassLoader;
import java.io.IOException; import java.io.IOException;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.util.StringTokenizer; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Hashtable;
import java.util.Map; import java.util.Map;
import java.util.StringTokenizer;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.ArrayList;
public class RMIClassLoader public class RMIClassLoader
{ {
static private class MyClassLoader extends URLClassLoader static private class MyClassLoader extends URLClassLoader
{ {
private MyClassLoader(URL[] urls, ClassLoader parent, String annotation)
{
super(urls, parent);
this.annotation = annotation;
}
private MyClassLoader(URL[] urls, ClassLoader parent) private MyClassLoader(URL[] urls, ClassLoader parent)
{ {
super (urls, parent); super (urls, parent);
this.annotation = urlToAnnotation(urls);
} }
Class defineClass(String name, byte[] data) public static String urlToAnnotation(URL[] urls)
{ {
return defineClass(name, data, 0, data.length); if (urls.length == 0)
return null;
StringBuffer annotation = new StringBuffer(64*urls.length);
for(int i = 0; i < urls.length; i++)
{
annotation.append(urls[i].toExternalForm());
annotation.append(' ');
}
return annotation.toString();
}
public final String getClassAnnotation(){
return annotation;
} }
private final String annotation;
} }
private static Map cacheLoaders; //map annotations to loaders private static Map cacheLoaders; //map annotations to loaders
private static Map cacheClasses; //map loader to classes that the loader loaded+ private static Map cacheAnnotations; //map loaders to annotations
//defaultAnnotation is got from system property
// "java.rmi.server.defaultAnnotation"
private static String defaultAnnotation; private static String defaultAnnotation;
//URL object for defaultAnnotation
private static URL defaultCodebase; private static URL defaultCodebase;
//class loader for defaultAnnotation
private static MyClassLoader defaultLoader; private static MyClassLoader defaultLoader;
static static
{ {
cacheLoaders = Collections.synchronizedMap(new WeakHashMap(5)); // 89 is a nice prime number for Hashtable initial capacity
cacheClasses = Collections.synchronizedMap(new WeakHashMap(5)); cacheLoaders = new Hashtable(89);
cacheAnnotations = new Hashtable(89);
defaultAnnotation = System.getProperty("java.rmi.server.defaultAnnotation"); defaultAnnotation = System.getProperty("java.rmi.server.defaultAnnotation");
try try
{ {
...@@ -89,9 +122,8 @@ public class RMIClassLoader ...@@ -89,9 +122,8 @@ public class RMIClassLoader
if (defaultCodebase != null) if (defaultCodebase != null)
{ {
defaultLoader = new MyClassLoader(new URL[]{ defaultCodebase }, defaultLoader = new MyClassLoader(new URL[]{ defaultCodebase },
Thread.currentThread().getContextClassLoader()); null, defaultAnnotation);
cacheLoaders.put(defaultAnnotation, defaultLoader); cacheLoaders.put(defaultAnnotation, defaultLoader);
cacheClasses.put(defaultLoader, Collections.synchronizedMap(new WeakHashMap()));
} }
} }
...@@ -104,91 +136,76 @@ public class RMIClassLoader ...@@ -104,91 +136,76 @@ public class RMIClassLoader
return (loadClass("", name)); return (loadClass("", name));
} }
public static Class loadClass(URL codebase, String name) public static Class loadClass(String codebases, String name)
throws MalformedURLException, ClassNotFoundException throws MalformedURLException, ClassNotFoundException
{ {
URL u = new URL(codebase, name + ".class"); Class c = null;
ClassLoader loader = Thread.currentThread().getContextClassLoader();
//try context class loader first
try try
{ {
URLConnection conn = u.openConnection(); c = loader.loadClass(name);
DataInputStream strm = new DataInputStream(conn.getInputStream());
byte data[] = new byte[conn.getContentLength()];
strm.readFully(data);
return (defaultLoader.defineClass(name, data));
}
catch (IOException _)
{
throw new ClassNotFoundException(name);
} }
} catch(ClassNotFoundException e) {}
public static Class loadClass(String codebases, String name) if (c != null)
throws MalformedURLException, ClassNotFoundException return c;
{
ClassLoader loader = (ClassLoader)cacheLoaders.get(codebases); if (codebases.length() == 0) //==""
if (loader == null) loader = defaultLoader;
else
{ {
if (codebases != "") loader = (ClassLoader)cacheLoaders.get(codebases);
if (loader == null)
{ {
//codebases are separated by " " //create an entry in cacheLoaders mapping a loader to codebases.
// codebases are separated by " "
StringTokenizer tok = new StringTokenizer(codebases, " "); StringTokenizer tok = new StringTokenizer(codebases, " ");
ArrayList urls = new ArrayList(); ArrayList urls = new ArrayList();
while (tok.hasMoreTokens()) while (tok.hasMoreTokens())
urls.add(new URL(tok.nextToken())); urls.add(new URL(tok.nextToken()));
loader = new MyClassLoader((URL[])urls.toArray(new URL[urls.size()]), loader = new MyClassLoader((URL[])urls.toArray(new URL[urls.size()]),
Thread.currentThread().getContextClassLoader()); null, codebases);
cacheLoaders.put(codebases, loader); cacheLoaders.put(codebases, loader);
cacheClasses.put(loader, Collections.synchronizedMap(new WeakHashMap()));
}
else
{
//if codebases is empty, construct a classloader
// based on current context classloader,
// and we won't cache classloader for empty codebases
loader = new MyClassLoader(new URL[]{ defaultCodebase },
Thread.currentThread().getContextClassLoader());
} }
} }
Class c = null; return loader != null ? loader.loadClass(name) : Class.forName(name);
Map classes = (Map)cacheClasses.get(loader);
if (classes != null)
{
c = (Class)classes.get(name);
if (c == null)
{
c = loader.loadClass(name);
classes.put(name, c);
}
}else
c = loader.loadClass(name);
return c;
} }
public static String getClassAnnotation(Class cl) public static String getClassAnnotation(Class cl)
{ {
ClassLoader loader = cl.getClassLoader(); ClassLoader loader = cl.getClassLoader();
if (loader == null) if (loader == null || loader == ClassLoader.getSystemClassLoader())
{ {
if (defaultCodebase != null) return null; //??
return defaultCodebase.toExternalForm(); }
else
return null; if (loader instanceof MyClassLoader)
{
return ((MyClassLoader)loader).getClassAnnotation();
} }
String s = (String)cacheAnnotations.get(loader);
if (s != null)
return s;
if (loader instanceof URLClassLoader) if (loader instanceof URLClassLoader)
{ {
URL[] urls = ((URLClassLoader)loader).getURLs(); URL[] urls = ((URLClassLoader)loader).getURLs();
if(urls.length == 0) if(urls.length == 0)
return null; return null;
StringBuffer annotation = new StringBuffer(urls[0].toExternalForm());
for(int i = 1; i < urls.length; i++) StringBuffer annotation = new StringBuffer(64*urls.length);
for(int i = 0; i < urls.length; i++)
{ {
annotation.append(' ');
annotation.append(urls[i].toExternalForm()); annotation.append(urls[i].toExternalForm());
annotation.append(' ');
} }
return annotation.toString(); s = annotation.toString();
cacheAnnotations.put(loader, s);
} }
return null; return null;
} }
......
...@@ -127,11 +127,11 @@ public boolean equals(Object obj) { ...@@ -127,11 +127,11 @@ public boolean equals(Object obj) {
} }
catch (InstantiationException e1) catch (InstantiationException e1)
{ {
throw new UnmarshalException("failed to create ref"); throw new UnmarshalException("failed to create ref", e1);
} }
catch (IllegalAccessException e2) catch (IllegalAccessException e2)
{ {
throw new UnmarshalException("failed to create ref"); throw new UnmarshalException("failed to create ref", e2);
} }
ref.readExternal(in); ref.readExternal(in);
} }
......
/* /*
Copyright (c) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -67,16 +67,12 @@ protected UnicastRemoteObject(int port, RMIClientSocketFactory csf, RMIServerSoc ...@@ -67,16 +67,12 @@ protected UnicastRemoteObject(int port, RMIClientSocketFactory csf, RMIServerSoc
//this.csf = csf; //this.csf = csf;
//this.ssf = ssf; //this.ssf = ssf;
this.ref = new UnicastServerRef(new ObjID(), port, ssf); this.ref = new UnicastServerRef(new ObjID(), port, ssf);
//Should we export it here? exportObject(this);
// if we export, we got infinite recursive call:
// UnicastRemoteObject.<init>->...->UnicastServer.startDGC()->UnicastRemoteObject.<init>->...
//exportObject(this);
} }
protected UnicastRemoteObject(RemoteRef ref) throws RemoteException { protected UnicastRemoteObject(RemoteRef ref) throws RemoteException {
super((UnicastServerRef)ref); super((UnicastServerRef)ref);
//Should we export it here? exportObject(this);
//exportObject(this);
} }
public Object clone() throws CloneNotSupportedException { public Object clone() throws CloneNotSupportedException {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment