CS 696 Emerging Technologies: Java Distributed Computing Spring Semester, 1999 Roaming Remotes |
||
---|---|---|
© 1999, All Rights Reserved, SDSU & Roger Whitney San Diego State University -- This page last updated 18-Feb-99 |
Framework for RMI Examples & Tests
Client Side
ServerTester
package whitney.rmi.examples.basic; import java.rmi.NotBoundException; import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.registry.Registry; public abstract class ServerTester { protected Registry serverRegistry; protected String serverLabel; protected Remote serverObject; public void initialize( Registry server, String serverLabel ) throws RemoteException, NotBoundException { serverRegistry = server; this.serverLabel =serverLabel; serverObject = serverRegistry.lookup( serverLabel ); } public abstract void test() throws Exception; }
ClientLauncher
package whitney.rmi.examples.basic; import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.NotBoundException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import sdsu.util.ProgramProperties; public class ClientLauncher { Registry serverRegistry; String serverLabel; public static void main(String args[]) throws Exception { ProgramProperties flags = new ProgramProperties( args ); String host = flags.getString( "host" ); int port = flags.getInt( "port", Registry.REGISTRY_PORT ); String serverLabel = flags.getString( "label" ); Registry serverRegistry = LocateRegistry.getRegistry( host, port ); String clientClass = flags.getString( "class" ); ServerTester client = (ServerTester) Class.forName( clientClass).newInstance(); client.initialize( serverRegistry, serverLabel ); client.test( ); } }
ServerSide
package whitney.rmi.examples.basic; import java.io.FileOutputStream; import java.io.BufferedOutputStream; import java.io.FileNotFoundException; import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.RMISecurityManager; import java.rmi.registry.Registry; import java.rmi.registry.LocateRegistry; import java.rmi.server.UnicastRemoteObject; import java.rmi.server.RemoteServer; import java.util.Properties; import sdsu.util.ProgramProperties; public class ServerLauncher { public static void main( String[] args ) throws Exception { System.setSecurityManager(new RMISecurityManager()); ProgramProperties flags = new ProgramProperties( args, "config" ); int port = flags.getInt( "port", Registry.REGISTRY_PORT); String serverLabel = flags.getString( "label" ); if ( flags.containsKey( "log" ) ) setLogging( flags.getString( "logfile", "rmiLog" ) ); String serverClass = flags.getString( "class" ); Remote serverObject = (Remote) Class.forName( serverClass).newInstance(); if ( ! (serverObject instanceof UnicastRemoteObject) ) UnicastRemoteObject.exportObject( serverObject ); Registry myRegistry = getRegistry( port ); myRegistry.rebind( serverLabel, serverObject ); System.out.println("Server bound as: " + serverLabel + " on port: " + port); }
//ServerLauncher Continued private static void setLogging( String fileName ) throws FileNotFoundException { Properties systemProperties = System.getProperties(); systemProperties.put( "java.rmi.server.logCalls", "true" ); FileOutputStream log = new FileOutputStream( fileName ); RemoteServer.setLog(new BufferedOutputStream( log )); } private static Registry getRegistry( int port ) throws RemoteException { try { return LocateRegistry.createRegistry(port ); } catch (Exception noRegistry) { return LocateRegistry.getRegistry( port ); } } }
Remotes without UnicastRemoteObject Parents
There may be times when you want a remote object to have a parent other than UnicastRemoteObject. There are performance reasons for doing this. It can reduce the time for serialization
If a Remote implemenation does not subclass UnicastRemoteObject then it must be exported via UnicastRemoteObject.exportObject() before it is registered with the RMI registry. The following example illustrates this.
Counter Interface
package whitney.rmi.examples.basic; import java.rmi.Remote; import java.rmi.RemoteException; public interface Counter extends Remote { public abstract void reset() throws RemoteException; public abstract int increase() throws RemoteException; public abstract int decrease() throws RemoteException; public abstract int count() throws RemoteException; }
IDlessCounter
package whitney.rmi.examples.basic; public class IDlessCounter implements Counter { private int count = 0; public void reset() { count = 0; } public int increase() { return ++count; } public int decrease() { return --count; } public int count() { return count; } }
RemoteCounter
If a Remote implementation does not subclass UnicastRemoteObject then it does not inherit from RemoteServer. That class implements equals, hashCode and toString() that are appropriate for remote objects. The following class implements these methods. However, I have not been able to access these methods form a remote instance of a RemoteCounter object. Since RemoteCounter does not directly extend a remote interface, on does not have to create stubs for the class.
package whitney.rmi.examples.basic; public class RemoteCounter extends IdlessCounter { private static int NEXT_ID = 1; private int id = NEXT_ID++; private int count = 0; public int hashCode() { return id; } public boolean equals( Object anObject ) { System.out.println( "RemoteCounter equals" ); if ( !(anObject instanceof RemoteCounter) ) return false; if ( id == ((RemoteCounter) anObject).id ) return true; else return false; } public String toString() { return "RemoteCounter(" + id + "," + count() + ")"; } }
CounterClient
package whitney.rmi.examples.basic; import java.rmi.RemoteException; import java.rmi.NotBoundException; import java.rmi.registry.Registry; public class CounterClient extends ServerTester { public void test() throws RemoteException, NotBoundException { simpleCount(); equalityTest(); } public void equalityTest( ) throws RemoteException, NotBoundException { Counter a = (Counter) serverRegistry.lookup( "a" ); Counter a1 = (Counter) serverRegistry.lookup( "a" ); Counter b = (Counter) serverRegistry.lookup( "b" ); if ( a.equals( a1) ) System.out.println( "a equals a1"); else System.out.println( "a not equals a1"); if ( a.equals( b) ) System.out.println( "a equals b"); else System.out.println( "a not equals b"); System.out.println( a ); System.out.println( b.hashCode() ); }
CounterClient Continued
public void simpleCount( ) throws RemoteException, NotBoundException { Counter remoteCount = (Counter) serverRegistry.lookup( "a" ); remoteCount.increase(); remoteCount.increase(); remoteCount.increase(); System.out.println( "The count " + remoteCount.count() ); } }Running the Example
Running the Server eli-> basic ServerLauncher -label=a -class=whitney.rmi.examples.basic.RemoteCounter & eli-> basic ServerLauncher -label=b -class=whitney.rmi.examples.basic.RemoteCounter & Server bound as: a on port: 1099 Server bound as: b on port: 1099Running the Client eli-> basic ClientLauncher -host=eli.sdsu.edu -class=whitney.rmi.examples.basic.CounterClient -label=aClient Output The count 3 a equals a1 a not equals b whitney.rmi.examples.basic.RemoteCounter_Stub[RemoteStub [ref: [endpoint:[130.191.234.12:34721](remote),objID:[12816c6:d60f1e025a:-8000, 0]]]] 0
Remotes & Garbage Collection Issues
A client or server can export a remote object without registering the object with an RMI registry. We will see several examples of this. Doing this raises some interesting questions. First, when can the object be garbage collected?
EchoCounter package whitney.rmi.examples.basic; import java.rmi.Remote; import java.rmi.RemoteException; public interface EchoCounter extends Remote { public abstract Counter newCounter() throws RemoteException; public abstract Counter getCounter() throws RemoteException; public abstract void setCounter( Counter aCounter ) throws RemoteException; }
EchoCounterServer package whitney.rmi.examples.basic; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class EchoCounterServer implements EchoCounter { Counter myCounter; protected Counter createCounter(){ return new RemoteCounter(); } public Counter newCounter() throws RemoteException { Counter aCounter = createCounter(); UnicastRemoteObject.exportObject( aCounter ); return aCounter; } public Counter getCounter() throws RemoteException { if ( myCounter == null ) myCounter = newCounter(); return myCounter; } public void setCounter( Counter aCounter ) { myCounter = aCounter; } }
SimpleEchoClient Here we see the client access a remote that is not registered with an RMI registry. What would happen if it requested millions of new counter objects? RMI keeps a remote reference count, which the garbage collector uses to determine if the object can be reclaimed. Each time a client’s reference to the remote object goes out of scope, it must in form the remote object, so it can reduce the remote count. That is RMI does remote garbage collection.
package whitney.rmi.examples.basic; import java.rmi.registry.Registry; import java.rmi.RemoteException; public class SimpleEchoClient extends ServerTester { public void test() throws RemoteException, InterruptedException { EchoCounter myServer = (EchoCounter) serverObject; Counter count = myServer.newCounter(); count.increase(); System.out.println( count ); Thread.sleep( 1000*60*15); count.increase(); System.out.println( count ); }
Distributed Garbage Collection
Each remote object has a referenced set
Each time a remote object is passed as a parameter or returned as a result of a remote request the identifier for the virtual machine to which it was passed is added to its referenced set
Once the remote virtual machine no longer has a reference to the remote object, it will be removed from the objects reference set
If the remote object implements the
java.rmi.server.Unreferenced interface
when its referenced set becomes empty it's unreferenced method will be called
The unreferenced method can be called more than once
It is not called the instance the last client reference is deleted
Delays of 10 - 15 minutes have been reported
When a remote object has no remote or local references it can be garbage collected
A remotes finalize method will be called when it is garbage collected
Unreferenced Example package whitney.rmi.examples.basic; import java.rmi.server.Unreferenced; public class GCCounter extends RemoteCounter implements Unreferenced { public GCCounter() { System.out.println( "Creating CGCounter: " + this.toString() ); } public void unreferenced() { System.out.println( "No more references to: " + this.toString() ); } }
Client Exporting Remote Objects
The following example shows a client passing a remote object to a server. The server then passes it back. If the unexportObject() method is not called the process will continue for a long time. The example here is not polite, as it unexports without making sure there are no references to the remote object.
package whitney.rmi.examples.basic; import java.rmi.RemoteException; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; public class ExportEchoClient extends ServerTester { public void test() throws RemoteException { EchoCounter myServer = (EchoCounter) serverObject; Counter count = new RemoteCounter(); UnicastRemoteObject.exportObject( count ); myServer.setCounter( count ); Counter remoteCopy = myServer.getCounter(); remoteCopy.increase(); if ( count.equals( remoteCopy)) System.out.println( "Local equals remote copy" ); else System.out.println( "Local not equal to remote copy" ); boolean force = true; boolean result = UnicastRemoteObject.unexportObject( count, force ); if (!result) System.out.println( "Could not unexport" ); } }
Copyright ©, All rights reserved.
1999 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
OpenContent license defines the copyright on this document.
Previous    visitors since 18-Feb-99    Next