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
This commit is contained in:
parent
396a80436c
commit
f150fe3fa7
18 changed files with 601 additions and 200 deletions
|
@ -1,3 +1,53 @@
|
|||
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().
|
||||
|
|
|
@ -61,42 +61,22 @@ public class RMIMarshalledObjectOutputStream extends RMIObjectOutputStream
|
|||
public RMIMarshalledObjectOutputStream(OutputStream objStream) throws IOException
|
||||
{
|
||||
super(objStream);
|
||||
locBytesStream = new ByteArrayOutputStream(256);
|
||||
locStream = new ObjectOutputStream(locBytesStream);
|
||||
}
|
||||
|
||||
//This method overrides RMIObjectOutputStream's.
|
||||
protected void setAnnotation(String annotation) throws IOException{
|
||||
synchronized(this){
|
||||
if(locStream == null){
|
||||
locBytesStream = new ByteArrayOutputStream();
|
||||
locStream = new ObjectOutputStream(locBytesStream);
|
||||
}
|
||||
}
|
||||
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 {
|
||||
super.flush();
|
||||
if(locStream != null)
|
||||
locStream.flush();
|
||||
}
|
||||
|
||||
public byte[] getLocBytes(){
|
||||
if(locStream != null)
|
||||
return locBytesStream.toByteArray();
|
||||
return null;
|
||||
}
|
||||
|
||||
} // End of RMIMarshalledObjectOutputStream
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
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.
|
||||
|
||||
|
@ -46,24 +46,73 @@ import java.rmi.server.UnicastRemoteObject;
|
|||
import java.rmi.server.RMISocketFactory;
|
||||
import gnu.java.rmi.server.UnicastServerRef;
|
||||
|
||||
public class DGCImpl
|
||||
extends UnicastRemoteObject implements DGC {
|
||||
import java.util.Hashtable;
|
||||
|
||||
private static final long leaseValue = 600000L;
|
||||
/**
|
||||
* I let DGCImpl to extend UnicastServerRef, but not
|
||||
* UnicastRemoteObject, because UnicastRemoteObject must
|
||||
* exportObject automatically.
|
||||
*/
|
||||
public class DGCImpl
|
||||
extends UnicastServerRef implements DGC {
|
||||
|
||||
private static final long LEASE_VALUE = 600000L;
|
||||
// leaseCache caches a LeaseRecord associated with a vmid
|
||||
private Hashtable leaseCache = new Hashtable();
|
||||
|
||||
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 {
|
||||
VMID vmid = lease.getVMID();
|
||||
if (vmid == null)
|
||||
vmid = new VMID();
|
||||
long leaseValue = LEASE_VALUE;
|
||||
//long leaseValue = lease.getValue();
|
||||
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);
|
||||
}
|
||||
|
||||
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 {
|
|||
|
||||
public RegistryImpl(int port, RMIClientSocketFactory cf, RMIServerSocketFactory sf) throws RemoteException {
|
||||
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 {
|
||||
|
|
|
@ -67,7 +67,7 @@ public final class RegistryImpl_Stub
|
|||
static {
|
||||
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 });
|
||||
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_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});
|
||||
|
|
|
@ -91,6 +91,7 @@ class ConnectionRunnerPool
|
|||
|
||||
}
|
||||
|
||||
// Should this value equal to number of CPU?
|
||||
private static int size = 5;
|
||||
private static int max_size = 10;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
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.
|
||||
|
||||
|
@ -50,23 +50,13 @@ import java.lang.reflect.Proxy;
|
|||
public class RMIObjectInputStream
|
||||
extends ObjectInputStream {
|
||||
|
||||
UnicastConnectionManager manager;
|
||||
|
||||
public RMIObjectInputStream(InputStream strm, UnicastConnectionManager man) throws IOException {
|
||||
super(strm);
|
||||
manager = man;
|
||||
enableResolveObject(true);
|
||||
}
|
||||
|
||||
public RMIObjectInputStream(InputStream strm) throws IOException {
|
||||
this(strm, UnicastConnectionManager.getInstance(0, null));
|
||||
super(strm);
|
||||
enableResolveObject(true);
|
||||
}
|
||||
|
||||
protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
|
||||
String annotation = (String)getAnnotation();
|
||||
try{
|
||||
return super.resolveClass(desc);
|
||||
}catch(ClassNotFoundException _){};
|
||||
|
||||
try {
|
||||
if(annotation == null)
|
||||
|
@ -90,24 +80,23 @@ 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]);
|
||||
for (int i = 0; i < intfs.length; i++)
|
||||
clss[i] = Class.forName(intfs[i], false, loader);
|
||||
|
||||
try {
|
||||
return Proxy.getProxyClass(loader, clss);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ClassNotFoundException(null, e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Object readValue(Class valueClass) throws IOException, ClassNotFoundException {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
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.
|
||||
|
||||
|
@ -72,10 +72,9 @@ 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){}
|
||||
UnicastServerRef ref = UnicastServer.getExportedRef((Remote)obj);
|
||||
if (ref != null)
|
||||
return ref.getStub();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
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.
|
||||
|
||||
|
@ -61,6 +61,10 @@ DataOutputStream dout;
|
|||
ObjectInputStream oin;
|
||||
ObjectOutputStream oout;
|
||||
|
||||
// reviveTime and expireTime make UnicastConnection pool-able
|
||||
long reviveTime = 0;
|
||||
long expireTime = Long.MAX_VALUE;
|
||||
|
||||
UnicastConnection(UnicastConnectionManager man, Socket sock) {
|
||||
this.manager = man;
|
||||
this.sock = sock;
|
||||
|
@ -137,7 +141,7 @@ DataOutputStream getDataOutputStream() throws IOException {
|
|||
|
||||
ObjectInputStream getObjectInputStream() throws IOException {
|
||||
if (oin == null) {
|
||||
oin = new RMIObjectInputStream(din, manager);
|
||||
oin = new RMIObjectInputStream(din);
|
||||
}
|
||||
return (oin);
|
||||
}
|
||||
|
@ -153,6 +157,7 @@ void disconnect() {
|
|||
try {
|
||||
if(oout != null)
|
||||
oout.close();
|
||||
sock.close();
|
||||
}
|
||||
catch (IOException _) {
|
||||
}
|
||||
|
@ -164,17 +169,35 @@ void disconnect() {
|
|||
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.
|
||||
*/
|
||||
public void run() {
|
||||
do{
|
||||
try {
|
||||
UnicastServer.dispatch(this);
|
||||
//don't discardConnection explicitly, only when
|
||||
// exception happens or the connection's expireTime
|
||||
// comes
|
||||
} catch (Exception e ){
|
||||
manager.discardConnection(this);
|
||||
break;
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}while(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
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.
|
||||
|
||||
|
@ -41,18 +41,25 @@ import java.rmi.server.RMISocketFactory;
|
|||
import java.rmi.server.RMIServerSocketFactory;
|
||||
import java.rmi.server.RMIClientSocketFactory;
|
||||
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.ObjectOutput;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.lang.Thread;
|
||||
import java.lang.Runnable;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.ServerSocket;
|
||||
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
|
||||
implements Runnable, ProtocolConstants {
|
||||
|
||||
|
@ -60,15 +67,33 @@ 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 ArrayList connections; //client connection pool
|
||||
|
||||
// make serverThread volatile for poll
|
||||
private volatile Thread serverThread;
|
||||
private ServerSocket ssock;
|
||||
String serverName;
|
||||
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 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 {
|
||||
try {
|
||||
//Use host address instead of host name to avoid name resolving issues
|
||||
|
@ -78,16 +103,73 @@ static {
|
|||
catch (UnknownHostException _) {
|
||||
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) {
|
||||
ssock = null;
|
||||
serverName = host;
|
||||
serverPort = port;
|
||||
serverFactory = null;
|
||||
clientFactory = csf;
|
||||
connections = new ArrayList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Server UnicastConnectionManager constructor
|
||||
*/
|
||||
private UnicastConnectionManager(int port, RMIServerSocketFactory ssf) {
|
||||
try {
|
||||
ssock = ssf.createServerSocket(port);
|
||||
|
@ -115,7 +197,7 @@ private UnicastConnectionManager(int port, RMIServerSocketFactory ssf) {
|
|||
public static synchronized UnicastConnectionManager getInstance(String host, int port, RMIClientSocketFactory csf) {
|
||||
//System.out.println("getInstance: " + host + "," + port + "," + csf);
|
||||
if (csf == null) {
|
||||
csf = RMISocketFactory.getSocketFactory();
|
||||
csf = defaultSocketFactory;
|
||||
}
|
||||
// change host name to host address to avoid name resolving issues
|
||||
try{
|
||||
|
@ -126,7 +208,17 @@ public static synchronized UnicastConnectionManager getInstance(String host, int
|
|||
UnicastConnectionManager man = (UnicastConnectionManager)clients.get(key);
|
||||
if (man == null) {
|
||||
man = new UnicastConnectionManager(host, port, csf);
|
||||
if (debug) {
|
||||
ncmanager++;
|
||||
System.out.println("\n\n ====== " + ncmanager + " client managers.\n\n");
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -138,12 +230,16 @@ public static synchronized UnicastConnectionManager getInstance(String host, int
|
|||
public static synchronized UnicastConnectionManager getInstance(int port, RMIServerSocketFactory ssf) {
|
||||
//System.out.println("getInstance: " + port + "," + ssf);
|
||||
if (ssf == null) {
|
||||
ssf = RMISocketFactory.getSocketFactory();
|
||||
ssf = defaultSocketFactory;
|
||||
}
|
||||
TripleKey key = new TripleKey(localhost, port, ssf);
|
||||
UnicastConnectionManager man = (UnicastConnectionManager)servers.get(key);
|
||||
if (man == null) {
|
||||
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.
|
||||
key.port = man.serverPort;
|
||||
servers.put(key, man);
|
||||
|
@ -168,9 +264,14 @@ public UnicastConnection getConnection() throws IOException {
|
|||
*/
|
||||
private UnicastConnection getServerConnection() throws IOException {
|
||||
Socket sock = ssock.accept();
|
||||
sock.setTcpNoDelay(true); //??
|
||||
UnicastConnection conn = new UnicastConnection(this, sock);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -178,10 +279,38 @@ private UnicastConnection getServerConnection() throws IOException {
|
|||
* Make a conection from this client to the server.
|
||||
*/
|
||||
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);
|
||||
UnicastConnection conn = new UnicastConnection(this, sock);
|
||||
conn = new UnicastConnection(this, sock);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -191,7 +320,19 @@ private UnicastConnection getClientConnection() throws IOException {
|
|||
*/
|
||||
public void discardConnection(UnicastConnection conn) {
|
||||
//System.out.println("Discarding connection " + conn);
|
||||
//conn.disconnect();
|
||||
if (ssock != null) //server connection
|
||||
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() {
|
|||
return;
|
||||
}
|
||||
serverThread = new Thread(this);
|
||||
// The following is not necessary when java.lang.Thread's constructor do this.
|
||||
// serverThread.setContextClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
serverThread.start();
|
||||
}
|
||||
|
@ -231,11 +374,11 @@ public void run() {
|
|||
//System.out.println("Waiting for connection on " + serverPort);
|
||||
UnicastConnection conn = getServerConnection();
|
||||
// use a thread pool to improve performance
|
||||
// (new Thread(conn)).start();
|
||||
ConnectionRunnerPool.dispatchConnection(conn);
|
||||
//ConnectionRunnerPool.dispatchConnection(conn);
|
||||
(new Thread(conn)).start();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -254,8 +397,9 @@ void write(ObjectOutput out) throws IOException {
|
|||
static UnicastConnectionManager read(ObjectInput in) throws IOException {
|
||||
String host = in.readUTF();
|
||||
int port = in.readInt();
|
||||
RMIClientSocketFactory csf = ((RMIObjectInputStream)in).manager.clientFactory;
|
||||
return (getInstance(host, port, csf));
|
||||
//RMIClientSocketFactory csf = ((RMIObjectInputStream)in).manager.clientFactory;
|
||||
//return (getInstance(host, port, csf));
|
||||
return (getInstance(host, port, null));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -288,7 +432,7 @@ public boolean equals(Object obj) {
|
|||
TripleKey other = (TripleKey)obj;
|
||||
if (this.host.equals(other.host) &&
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
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.
|
||||
|
||||
|
@ -62,6 +62,8 @@ import java.io.ObjectOutputStream;
|
|||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class UnicastRef
|
||||
implements RemoteRef, ProtocolConstants {
|
||||
|
||||
|
@ -69,9 +71,10 @@ public ObjID objid;
|
|||
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) {
|
||||
|
@ -84,6 +87,21 @@ public UnicastRef(ObjID objid) {
|
|||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -107,18 +125,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) {
|
||||
out.writeObject(UnicastRemoteObject.exportObject((UnicastRemoteObject)params[i]));
|
||||
}
|
||||
else {
|
||||
out.writeObject(params[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// must handle primitive class and their wrapper classes
|
||||
Class clss[] = method.getParameterTypes();
|
||||
for(int i = 0; i < clss.length; i++)
|
||||
|
@ -137,26 +144,30 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu
|
|||
UID ack;
|
||||
try {
|
||||
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();
|
||||
|
||||
returncode = in.readUnsignedByte();
|
||||
ack = UID.read(in);
|
||||
//returnval = in.readObject();
|
||||
|
||||
Class cls = method.getReturnType();
|
||||
if(cls == Void.TYPE){
|
||||
returnval = null;
|
||||
in.readObject();
|
||||
}else
|
||||
returnval = ((RMIObjectInputStream)in).readValue(cls);
|
||||
|
||||
}
|
||||
catch (IOException e3) {
|
||||
//for debug: e3.printStackTrace();
|
||||
throw new RemoteException("call return failed: ", e3);
|
||||
}
|
||||
|
||||
/* if DGCAck is necessary
|
||||
/* if DGCAck is necessary??
|
||||
//According to RMI wire protocol, send a DGCAck
|
||||
// to indicate receiving return value
|
||||
dout.writeByte(MESSAGE_DGCACK);
|
||||
|
@ -166,7 +177,7 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu
|
|||
|
||||
manager.discardConnection(conn);
|
||||
|
||||
if (returncode != RETURN_ACK) {
|
||||
if (returncode != RETURN_ACK && returnval != null) {
|
||||
throw (Exception)returnval;
|
||||
}
|
||||
|
||||
|
@ -177,7 +188,18 @@ private Object invokeCommon(Remote obj, Method method, Object[] params, int opnu
|
|||
* @deprecated
|
||||
*/
|
||||
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
|
|||
*/
|
||||
public void invoke(RemoteCall call) throws Exception {
|
||||
UnicastRemoteCall c = (UnicastRemoteCall)call;
|
||||
Object ret = invokeCommon((Remote)c.getObject(), (Method)null, c.getArguments(), c.getOpnum(), c.getHash());
|
||||
c.setReturnValue(ret);
|
||||
call.executeCall();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
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 {
|
||||
|
|
|
@ -38,14 +38,24 @@ exception statement from your version. */
|
|||
package gnu.java.rmi.server;
|
||||
|
||||
import java.lang.Exception;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.StreamCorruptedException;
|
||||
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;
|
||||
|
||||
public class UnicastRemoteCall implements RemoteCall
|
||||
public class UnicastRemoteCall
|
||||
implements RemoteCall, ProtocolConstants
|
||||
{
|
||||
|
||||
private UnicastConnection conn;
|
||||
|
@ -56,6 +66,9 @@ public class UnicastRemoteCall implements RemoteCall
|
|||
private Vector vec;
|
||||
private int ptr;
|
||||
|
||||
private ObjectOutput oout;
|
||||
private ObjectInput oin;
|
||||
|
||||
/**
|
||||
* Incoming call.
|
||||
*/
|
||||
|
@ -67,30 +80,71 @@ public class UnicastRemoteCall implements RemoteCall
|
|||
/**
|
||||
* 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.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
|
||||
{
|
||||
if (conn != null)
|
||||
{
|
||||
if(oout == null)
|
||||
return (oout = conn.getObjectOutputStream());
|
||||
else
|
||||
return oout;
|
||||
}
|
||||
else
|
||||
{
|
||||
vec = new Vector();
|
||||
return new DummyObjectOutputStream();
|
||||
return (new DummyObjectOutputStream());
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseOutputStream() throws IOException
|
||||
{
|
||||
// Does nothing.
|
||||
if(oout != null)
|
||||
oout.flush();
|
||||
}
|
||||
|
||||
public ObjectInput getInputStream() throws IOException
|
||||
{
|
||||
if (conn != null)
|
||||
return conn.getObjectInputStream();
|
||||
{
|
||||
if(oin == null)
|
||||
return (oin = conn.getObjectInputStream());
|
||||
else
|
||||
return oin;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = 0;
|
||||
return new DummyObjectInputStream();
|
||||
return (new DummyObjectInputStream());
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseInputStream() throws IOException
|
||||
|
@ -107,12 +161,54 @@ public class UnicastRemoteCall implements RemoteCall
|
|||
|
||||
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
|
||||
{
|
||||
/* Does nothing */
|
||||
// conn.disconnect();
|
||||
}
|
||||
|
||||
Object returnValue()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
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.
|
||||
|
||||
|
@ -45,6 +45,7 @@ import java.io.IOException;
|
|||
import java.net.InetAddress;
|
||||
import java.util.Hashtable;
|
||||
import java.net.UnknownHostException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.server.ObjID;
|
||||
import java.rmi.server.UnicastRemoteObject;
|
||||
import java.rmi.server.UID;
|
||||
|
@ -56,27 +57,36 @@ import gnu.java.rmi.dgc.DGCImpl;
|
|||
public class UnicastServer
|
||||
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;
|
||||
|
||||
public static void exportObject(UnicastServerRef obj) {
|
||||
startDGC();
|
||||
objects.put(obj.objid, obj);
|
||||
refcache.put(obj.myself, obj);
|
||||
obj.manager.startServer();
|
||||
}
|
||||
|
||||
// FIX ME: I haven't handle force parameter
|
||||
public static boolean unexportObject(UnicastServerRef obj, boolean force) {
|
||||
objects.remove(obj.objid);
|
||||
refcache.remove(obj.myself);
|
||||
obj.manager.stopServer();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static UnicastServerRef getExportedRef(Remote remote){
|
||||
return (UnicastServerRef)refcache.get(remote);
|
||||
}
|
||||
|
||||
private static synchronized void startDGC() {
|
||||
if (dgc == null) {
|
||||
try {
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
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.
|
||||
|
||||
|
@ -63,6 +63,8 @@ import java.io.DataInputStream;
|
|||
import java.io.DataOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class UnicastServerRef
|
||||
|
@ -71,11 +73,18 @@ public class UnicastServerRef
|
|||
|
||||
final static private Class[] stubprototype = new Class[] { RemoteRef.class };
|
||||
|
||||
Remote myself;
|
||||
Remote myself; //save the remote object itself
|
||||
private Skeleton skel;
|
||||
private RemoteStub stub;
|
||||
private Hashtable methods = new Hashtable();
|
||||
|
||||
/**
|
||||
* Used by serialization.
|
||||
*/
|
||||
UnicastServerRef()
|
||||
{
|
||||
}
|
||||
|
||||
public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf) {
|
||||
super(id);
|
||||
manager = UnicastConnectionManager.getInstance(port, ssf);
|
||||
|
@ -84,6 +93,9 @@ public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf) {
|
|||
public RemoteStub exportObject(Remote obj) throws RemoteException {
|
||||
if (myself == null) {
|
||||
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
|
||||
Class cls = obj.getClass();
|
||||
|
@ -112,6 +124,10 @@ public RemoteStub exportObject(Remote remote, Object obj)
|
|||
return exportObject(remote);
|
||||
}
|
||||
|
||||
public RemoteStub getStub(){
|
||||
return stub;
|
||||
}
|
||||
|
||||
|
||||
public boolean unexportObject(Remote obj, boolean force) throws RemoteException {
|
||||
// Remove all hashes of methods which may be called.
|
||||
|
|
|
@ -79,6 +79,10 @@ public final class MarshalledObject
|
|||
if(obj == null || !(obj instanceof MarshalledObject) )
|
||||
return false;
|
||||
|
||||
// hashCode even differs, don't do the time-consuming comparisons
|
||||
if (obj.hashCode() != hash)
|
||||
return false;
|
||||
|
||||
MarshalledObject aobj = (MarshalledObject)obj;
|
||||
if (objBytes == null || aobj.objBytes == null)
|
||||
return objBytes == aobj.objBytes;
|
||||
|
|
|
@ -43,39 +43,72 @@ import java.net.URLClassLoader;
|
|||
import java.io.IOException;
|
||||
import java.io.DataInputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class RMIClassLoader
|
||||
{
|
||||
|
||||
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)
|
||||
{
|
||||
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 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;
|
||||
//URL object for defaultAnnotation
|
||||
private static URL defaultCodebase;
|
||||
//class loader for defaultAnnotation
|
||||
private static MyClassLoader defaultLoader;
|
||||
|
||||
static
|
||||
{
|
||||
cacheLoaders = Collections.synchronizedMap(new WeakHashMap(5));
|
||||
cacheClasses = Collections.synchronizedMap(new WeakHashMap(5));
|
||||
// 89 is a nice prime number for Hashtable initial capacity
|
||||
cacheLoaders = new Hashtable(89);
|
||||
cacheAnnotations = new Hashtable(89);
|
||||
|
||||
defaultAnnotation = System.getProperty("java.rmi.server.defaultAnnotation");
|
||||
try
|
||||
{
|
||||
|
@ -89,9 +122,8 @@ public class RMIClassLoader
|
|||
if (defaultCodebase != null)
|
||||
{
|
||||
defaultLoader = new MyClassLoader(new URL[]{ defaultCodebase },
|
||||
Thread.currentThread().getContextClassLoader());
|
||||
null, defaultAnnotation);
|
||||
cacheLoaders.put(defaultAnnotation, defaultLoader);
|
||||
cacheClasses.put(defaultLoader, Collections.synchronizedMap(new WeakHashMap()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,91 +136,76 @@ public class RMIClassLoader
|
|||
return (loadClass("", name));
|
||||
}
|
||||
|
||||
public static Class loadClass(URL codebase, String name)
|
||||
throws MalformedURLException, ClassNotFoundException
|
||||
{
|
||||
URL u = new URL(codebase, name + ".class");
|
||||
try
|
||||
{
|
||||
URLConnection conn = u.openConnection();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public static Class loadClass(String codebases, String name)
|
||||
throws MalformedURLException, ClassNotFoundException
|
||||
{
|
||||
ClassLoader loader = (ClassLoader)cacheLoaders.get(codebases);
|
||||
Class c = null;
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
//try context class loader first
|
||||
try
|
||||
{
|
||||
c = loader.loadClass(name);
|
||||
}
|
||||
catch(ClassNotFoundException e) {}
|
||||
|
||||
if (c != null)
|
||||
return c;
|
||||
|
||||
if (codebases.length() == 0) //==""
|
||||
loader = defaultLoader;
|
||||
else
|
||||
{
|
||||
loader = (ClassLoader)cacheLoaders.get(codebases);
|
||||
if (loader == null)
|
||||
{
|
||||
if (codebases != "")
|
||||
{
|
||||
//codebases are separated by " "
|
||||
//create an entry in cacheLoaders mapping a loader to codebases.
|
||||
|
||||
// codebases are separated by " "
|
||||
StringTokenizer tok = new StringTokenizer(codebases, " ");
|
||||
ArrayList urls = new ArrayList();
|
||||
while (tok.hasMoreTokens())
|
||||
urls.add(new URL(tok.nextToken()));
|
||||
|
||||
loader = new MyClassLoader((URL[])urls.toArray(new URL[urls.size()]),
|
||||
Thread.currentThread().getContextClassLoader());
|
||||
null, codebases);
|
||||
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;
|
||||
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;
|
||||
return loader != null ? loader.loadClass(name) : Class.forName(name);
|
||||
}
|
||||
|
||||
public static String getClassAnnotation(Class cl)
|
||||
{
|
||||
ClassLoader loader = cl.getClassLoader();
|
||||
if (loader == null)
|
||||
if (loader == null || loader == ClassLoader.getSystemClassLoader())
|
||||
{
|
||||
if (defaultCodebase != null)
|
||||
return defaultCodebase.toExternalForm();
|
||||
else
|
||||
return null;
|
||||
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)
|
||||
{
|
||||
URL[] urls = ((URLClassLoader)loader).getURLs();
|
||||
if(urls.length == 0)
|
||||
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(' ');
|
||||
}
|
||||
return annotation.toString();
|
||||
s = annotation.toString();
|
||||
cacheAnnotations.put(loader, s);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -127,11 +127,11 @@ public boolean equals(Object obj) {
|
|||
}
|
||||
catch (InstantiationException e1)
|
||||
{
|
||||
throw new UnmarshalException("failed to create ref");
|
||||
throw new UnmarshalException("failed to create ref", e1);
|
||||
}
|
||||
catch (IllegalAccessException e2)
|
||||
{
|
||||
throw new UnmarshalException("failed to create ref");
|
||||
throw new UnmarshalException("failed to create ref", e2);
|
||||
}
|
||||
ref.readExternal(in);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
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.
|
||||
|
||||
|
@ -67,16 +67,12 @@ protected UnicastRemoteObject(int port, RMIClientSocketFactory csf, RMIServerSoc
|
|||
//this.csf = csf;
|
||||
//this.ssf = ssf;
|
||||
this.ref = new UnicastServerRef(new ObjID(), port, ssf);
|
||||
//Should we export it here?
|
||||
// if we export, we got infinite recursive call:
|
||||
// UnicastRemoteObject.<init>->...->UnicastServer.startDGC()->UnicastRemoteObject.<init>->...
|
||||
//exportObject(this);
|
||||
exportObject(this);
|
||||
}
|
||||
|
||||
protected UnicastRemoteObject(RemoteRef ref) throws RemoteException {
|
||||
super((UnicastServerRef)ref);
|
||||
//Should we export it here?
|
||||
//exportObject(this);
|
||||
exportObject(this);
|
||||
}
|
||||
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue