From 5657d5b13cce5e15638353c4b4b37131a131f35d Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 7 Nov 2002 18:01:05 +0000 Subject: [PATCH] Merge Orp RMI patches from Wu Gansha * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@58900 138bc75d-0d04-0410-961f-82ee72b054a4 --- libjava/ChangeLog | 50 ++++++ .../java/rmi/RMIMarshalledObjectOutputStream.java | 28 +--- libjava/gnu/java/rmi/dgc/DGCImpl.java | 63 +++++++- libjava/gnu/java/rmi/registry/RegistryImpl.java | 3 +- .../gnu/java/rmi/registry/RegistryImpl_Stub.java | 2 +- .../gnu/java/rmi/server/ConnectionRunnerPool.java | 1 + .../gnu/java/rmi/server/RMIObjectInputStream.java | 33 ++-- .../gnu/java/rmi/server/RMIObjectOutputStream.java | 9 +- libjava/gnu/java/rmi/server/UnicastConnection.java | 33 +++- .../java/rmi/server/UnicastConnectionManager.java | 176 +++++++++++++++++++-- libjava/gnu/java/rmi/server/UnicastRef.java | 76 ++++++--- libjava/gnu/java/rmi/server/UnicastRemoteCall.java | 122 ++++++++++++-- libjava/gnu/java/rmi/server/UnicastServer.java | 16 +- libjava/gnu/java/rmi/server/UnicastServerRef.java | 20 ++- libjava/java/rmi/MarshalledObject.java | 4 + libjava/java/rmi/server/RMIClassLoader.java | 143 +++++++++-------- libjava/java/rmi/server/RemoteObject.java | 4 +- libjava/java/rmi/server/UnicastRemoteObject.java | 10 +- 18 files changed, 597 insertions(+), 196 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 742977d601d..11ec52e2135 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,5 +1,55 @@ 2002-11-07 Mark Wielaard + Merge Orp RMI patches from Wu Gansha + * 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 + * java/lang/reflect/natField.cc (getBoolean): Use getType(). (getByte): Likewise. (getShort): Likewise. diff --git a/libjava/gnu/java/rmi/RMIMarshalledObjectOutputStream.java b/libjava/gnu/java/rmi/RMIMarshalledObjectOutputStream.java index 66392919868..a721fc47194 100644 --- a/libjava/gnu/java/rmi/RMIMarshalledObjectOutputStream.java +++ b/libjava/gnu/java/rmi/RMIMarshalledObjectOutputStream.java @@ -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(); + locStream.flush(); } public byte[] getLocBytes(){ - if(locStream != null) - return locBytesStream.toByteArray(); - return null; + return locBytesStream.toByteArray(); } } // End of RMIMarshalledObjectOutputStream diff --git a/libjava/gnu/java/rmi/dgc/DGCImpl.java b/libjava/gnu/java/rmi/dgc/DGCImpl.java index fba18c1715d..4216b6466ba 100644 --- a/libjava/gnu/java/rmi/dgc/DGCImpl.java +++ b/libjava/gnu/java/rmi/dgc/DGCImpl.java @@ -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; +import java.util.Hashtable; + +/** + * I let DGCImpl to extend UnicastServerRef, but not + * UnicastRemoteObject, because UnicastRemoteObject must + * exportObject automatically. + */ 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 { - 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 diff --git a/libjava/gnu/java/rmi/registry/RegistryImpl.java b/libjava/gnu/java/rmi/registry/RegistryImpl.java index fdf4506f32d..007d5a97de9 100644 --- a/libjava/gnu/java/rmi/registry/RegistryImpl.java +++ b/libjava/gnu/java/rmi/registry/RegistryImpl.java @@ -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 { diff --git a/libjava/gnu/java/rmi/registry/RegistryImpl_Stub.java b/libjava/gnu/java/rmi/registry/RegistryImpl_Stub.java index 33cb06a4b68..45e10c49050 100644 --- a/libjava/gnu/java/rmi/registry/RegistryImpl_Stub.java +++ b/libjava/gnu/java/rmi/registry/RegistryImpl_Stub.java @@ -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}); diff --git a/libjava/gnu/java/rmi/server/ConnectionRunnerPool.java b/libjava/gnu/java/rmi/server/ConnectionRunnerPool.java index df6363bdcb6..af7dc0501ae 100644 --- a/libjava/gnu/java/rmi/server/ConnectionRunnerPool.java +++ b/libjava/gnu/java/rmi/server/ConnectionRunnerPool.java @@ -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; diff --git a/libjava/gnu/java/rmi/server/RMIObjectInputStream.java b/libjava/gnu/java/rmi/server/RMIObjectInputStream.java index 5913e9221bf..3e862c3c184 100644 --- a/libjava/gnu/java/rmi/server/RMIObjectInputStream.java +++ b/libjava/gnu/java/rmi/server/RMIObjectInputStream.java @@ -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 { +public RMIObjectInputStream(InputStream strm) throws IOException { super(strm); - manager = man; enableResolveObject(true); } -public RMIObjectInputStream(InputStream strm) throws IOException { - this(strm, UnicastConnectionManager.getInstance(0, null)); -} - 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 { @@ -134,4 +123,4 @@ protected Object readValue(Class valueClass) throws IOException, ClassNotFoundEx return readObject(); } -} \ No newline at end of file +} diff --git a/libjava/gnu/java/rmi/server/RMIObjectOutputStream.java b/libjava/gnu/java/rmi/server/RMIObjectOutputStream.java index 71a2bac9ded..97ac88aabc1 100644 --- a/libjava/gnu/java/rmi/server/RMIObjectOutputStream.java +++ b/libjava/gnu/java/rmi/server/RMIObjectOutputStream.java @@ -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; } diff --git a/libjava/gnu/java/rmi/server/UnicastConnection.java b/libjava/gnu/java/rmi/server/UnicastConnection.java index e13bb686229..14d28f26c91 100644 --- a/libjava/gnu/java/rmi/server/UnicastConnection.java +++ b/libjava/gnu/java/rmi/server/UnicastConnection.java @@ -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); } } diff --git a/libjava/gnu/java/rmi/server/UnicastConnectionManager.java b/libjava/gnu/java/rmi/server/UnicastConnectionManager.java index 64fecdce2a0..d54dcf1d4cd 100644 --- a/libjava/gnu/java/rmi/server/UnicastConnectionManager.java +++ b/libjava/gnu/java/rmi/server/UnicastConnectionManager.java @@ -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); } } diff --git a/libjava/gnu/java/rmi/server/UnicastRef.java b/libjava/gnu/java/rmi/server/UnicastRef.java index d6cda49c600..9ab020db6c3 100644 --- a/libjava/gnu/java/rmi/server/UnicastRef.java +++ b/libjava/gnu/java/rmi/server/UnicastRef.java @@ -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 { diff --git a/libjava/gnu/java/rmi/server/UnicastRemoteCall.java b/libjava/gnu/java/rmi/server/UnicastRemoteCall.java index 200538d4ae8..734002aaa65 100644 --- a/libjava/gnu/java/rmi/server/UnicastRemoteCall.java +++ b/libjava/gnu/java/rmi/server/UnicastRemoteCall.java @@ -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 { - vec = new Vector(); - return new DummyObjectOutputStream(); + if (conn != null) + { + if(oout == null) + return (oout = conn.getObjectOutputStream()); + else + return oout; + } + else + { + vec = new Vector(); + 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(); - ptr = 0; - return new DummyObjectInputStream(); + { + if(oin == null) + return (oin = conn.getObjectInputStream()); + else + return oin; + } + else + { + ptr = 0; + return (new DummyObjectInputStream()); + } } public void releaseInputStream() throws IOException @@ -104,15 +158,57 @@ public class UnicastRemoteCall implements RemoteCall vec = new Vector(); return new DummyObjectOutputStream(); } - + 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() diff --git a/libjava/gnu/java/rmi/server/UnicastServer.java b/libjava/gnu/java/rmi/server/UnicastServer.java index 15c622f48bc..baa1ef1aa4a 100644 --- a/libjava/gnu/java/rmi/server/UnicastServer.java +++ b/libjava/gnu/java/rmi/server/UnicastServer.java @@ -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(); diff --git a/libjava/gnu/java/rmi/server/UnicastServerRef.java b/libjava/gnu/java/rmi/server/UnicastServerRef.java index 196f969d292..4f64452b124 100644 --- a/libjava/gnu/java/rmi/server/UnicastServerRef.java +++ b/libjava/gnu/java/rmi/server/UnicastServerRef.java @@ -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. diff --git a/libjava/java/rmi/MarshalledObject.java b/libjava/java/rmi/MarshalledObject.java index 4c9a9ccdb40..9f966b9d9dc 100644 --- a/libjava/java/rmi/MarshalledObject.java +++ b/libjava/java/rmi/MarshalledObject.java @@ -78,6 +78,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) diff --git a/libjava/java/rmi/server/RMIClassLoader.java b/libjava/java/rmi/server/RMIClassLoader.java index da8f52c7ce9..1b00970e441 100644 --- a/libjava/java/rmi/server/RMIClassLoader.java +++ b/libjava/java/rmi/server/RMIClassLoader.java @@ -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) + public static Class loadClass(String codebases, String name) throws MalformedURLException, ClassNotFoundException { - URL u = new URL(codebase, name + ".class"); + Class c = null; + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + //try context class loader first 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); + c = loader.loadClass(name); } - } - - public static Class loadClass(String codebases, String name) - throws MalformedURLException, ClassNotFoundException - { - ClassLoader loader = (ClassLoader)cacheLoaders.get(codebases); - if (loader == null) + catch(ClassNotFoundException e) {} + + if (c != null) + return c; + + if (codebases.length() == 0) //=="" + 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, " "); 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; } diff --git a/libjava/java/rmi/server/RemoteObject.java b/libjava/java/rmi/server/RemoteObject.java index 8ae93ff8844..a1febf2dd62 100644 --- a/libjava/java/rmi/server/RemoteObject.java +++ b/libjava/java/rmi/server/RemoteObject.java @@ -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); } diff --git a/libjava/java/rmi/server/UnicastRemoteObject.java b/libjava/java/rmi/server/UnicastRemoteObject.java index a9c4f35099c..aefe9701ecd 100644 --- a/libjava/java/rmi/server/UnicastRemoteObject.java +++ b/libjava/java/rmi/server/UnicastRemoteObject.java @@ -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.->...->UnicastServer.startDGC()->UnicastRemoteObject.->... - //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 { -- 2.11.4.GIT