SDSU CS 696 Emerging Technologies: Java Distributed Computing
Spring Semester, 1999
Roaming Remotes
Previous    Lecture Notes Index    Next    
© 1999, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 18-Feb-99

Contents of Doc 9, Roaming Remotes


References:


Java Remote Method Invocation Specification
Local HTML Copy: http://www-rohan.sdsu.edu/java/jdk1.2/docs/guide/rmi/spec/rmiTOC.doc.html
Sun HTML Site: http://java.sun.com/products/jdk/1.2/docs/guide/rmi/spec/rmiTOC.doc.html
Hard copy is available at Cal Copy and on reserve at Love Library

JDK 1.2 API Documentation
Local Copy: http://www-rohan.sdsu.edu/java/jdk1.2/docs/api/overview-summary.html
Sun Site: http://java.sun.com/products/jdk/1.2/docs/api/overview-summary.html

RMI Source Code
On rohan at /opt/jdk1.2/src


Doc 9, Roaming Remotes Slide # 2

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;
   }

Doc 9, Roaming Remotes Slide # 3

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( );
      }
   }

Doc 9, Roaming Remotes Slide # 4

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);
      }

Doc 9, Roaming Remotes Slide # 5
//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 );
         }
      }
   }

Doc 9, Roaming Remotes Slide # 6

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;
   }

Doc 9, Roaming Remotes Slide # 7

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;
      }
   }

Doc 9, Roaming Remotes Slide # 8

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() + ")";  }
   }

Doc 9, Roaming Remotes Slide # 9

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() );
      }

Doc 9, Roaming Remotes Slide # 10
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: 1099
Running the Client
eli-> basic ClientLauncher -host=eli.sdsu.edu -class=whitney.rmi.examples.basic.CounterClient -label=a
Client 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

Doc 9, Roaming Remotes Slide # 11

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;
   }

Doc 9, Roaming Remotes Slide # 12
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;
   }
}

Doc 9, Roaming Remotes Slide # 13
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 );
      }

Doc 9, Roaming Remotes Slide # 14

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

Doc 9, Roaming Remotes Slide # 15
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() );
      }
   }

Doc 9, Roaming Remotes Slide # 16

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