SDSU CS 696 Emerging Technologies: Distributed Objects
Spring Semester, 1998
RMI Server Methods

To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 21-Apr-98

Contents of Doc 11, RMI Server Methods

  1. References
  2. Server Parent Classes
    1. java.rmi.server.RemoteObject
    2. java.rmi.server.RemoteServer
    3. java.rmi.server.UnicastRemoteObject
  3. Simple (But Long) Example
    1. ServerMethods Interface
    2. Client
    3. Client Output
    4. Server
    5. Command line to Start Server
    6. Server Output - Screen
    7. Server Output - log file
  4. Snooping on RMI Wire
  5. Logging - A More General System
  6. Remotes without UnicastRemoteObject
    1. Echo Example
      1. Remote Echo Interface
      2. EchoImpl
      3. EchoExample: Server Interface
      4. Server Implementation
      5. Client
      6. Output
  7. Roaming Remotes- Distributed Garbage Collection

References


Java RMI API

Java Remote Method Invocation Specification

RMI Users Mailing list


Doc 11, RMI Server Methods Slide # 2

Server Parent Classes


Servers typically extend UnicastRemoteObject:
public class HelloServer 
      extends UnicastRemoteObject
      implements Hello
   {
   }


The class Structure
java.lang.Object
   |
   +----java.rmi.server.RemoteObject
           |
           +----java.rmi.server.RemoteServer
                   |
                   +----java.rmi.server.UnicastRemoteObject


Doc 11, RMI Server Methods Slide # 3

java.rmi.server.RemoteObject


Implements java.lang.Object behavior for remote objects
Methods

equals(Object proxy)
Returns true if two java.rmi.Remote objects (or proxies) refer to the same remote object

hashCode()
If two proxies that refer to the same remote object are equal, then the normal way to compute hashCode needs to be modified, Returns a hashcode for a remote object.


toString()
Returns a String that represents the value of this remote object, implementation-specific


Doc 11, RMI Server Methods Slide # 4

java.rmi.server.RemoteServer



public static String getClientHost() throws ServerNotActiveException
Return the hostname of the current client. When called from a thread actively handling a remote method invocation the hostname of the client is returned.
Throws: ServerNotActiveException
If called outside of servicing a remote method invocation.

public static void setLog(OutputStream out)
Log RMI calls to the output stream out. If out is null, call logging is turned off.


public static PrintStream getLog()
Returns stream for the RMI call log.


Doc 11, RMI Server Methods Slide # 5

java.rmi.server.UnicastRemoteObject

Constructor

UnicastRemoteObject()
Create and export a new UnicastRemoteObject object using an anonymous port.


Methods
clone()
Returns a clone of the remote object that is distinct from the original.

exportObject(Remote)
Export the remote object to make it available to receive incoming calls.


Doc 11, RMI Server Methods Slide # 6

Simple (But Long) Example

ServerMethods Interface

package whitney.rmi.examples.server;
import java.rmi.server.ServerNotActiveException;

public interface ServerMethods extends 
   java.rmi.Remote 
   {
   public ServerMethods tryMe( int callNumber ) 
      throws java.rmi.RemoteException,
      ServerNotActiveException;
   }


Doc 11, RMI Server Methods Slide # 7

Client

package whitney.rmi.examples.server;

import java.rmi.*;
import java.rmi.registry.Registry;
import java.net.MalformedURLException;
import java.io.IOException;
import sdsu.util.ProgramProperties;
public class ServerMethodsClient 
   {
   public static void main(String args[]) 
      {
      try 
         {
         String serverLabel =    ServerMethodsServer.RMI_NAME;
         String server = getServerURL( args, serverLabel );
         
         ServerMethods first = 
            (ServerMethods) Naming.lookup( server );

         ServerMethods second = 
            (ServerMethods) Naming.lookup( server );
            
         ServerMethods third = first.tryMe( 1 );
         first.tryMe( 2 );
         second.tryMe( 3 );
         
         if ( first == second )
            System.out.println( "1 = 2" );
         else
            System.out.println( "1 != 2" );
            
         if ( first == third )
            System.out.println( "1 = 3" );
         else
            System.out.println( "1 != 3" );
         System.out.println( "1 " + first.hashCode() );
         System.out.println( "2 " + second.hashCode() );
         System.out.println( "3 " + third.hashCode() );
         } 
      catch ( Exception error) 
         {
         error.printStackTrace();
         }
      }


Doc 11, RMI Server Methods Slide # 8
//CLIENT CONTINUED
   private static String getServerURL( String args[], String serverLabel ) throws IOException
      {
      String hostKey = "h";
      String portKey = "p";
      
      ProgramProperties flags = new ProgramProperties( args );
      
      String host = null;
      if ( flags.containsKey( hostKey ) )
         host = flags.getString( hostKey );
      else
         {
         System.out.println( "Missing flag " + hostKey );
         System.exit( 0 );
         }
      
      int defaultPort = Registry.REGISTRY_PORT;
      int port = flags.getInt( portKey, defaultPort );
      
      return "rmi://" + host + ":" + port + "/" + serverLabel;
      }
   }

Client Output


1 != 2
1 != 3
1 0
2 0
3 0


Doc 11, RMI Server Methods Slide # 9

Server

package whitney.rmi.examples.server;

import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.ServerNotActiveException;
import java.rmi.registry.Registry;
import sdsu.rmi.registry.Registrar;
import sdsu.util.ProgramProperties;
import java.io.*;

public class ServerMethodsServer 
      extends UnicastRemoteObject
      implements ServerMethods
   {
   public ServerMethodsServer() throws RemoteException, IOException
      {
      FileOutputStream log = new FileOutputStream( "MyLog");
      setLog ( new BufferedOutputStream( log ) );
      }

   public ServerMethods tryMe( int callNumber  ) 
   throws RemoteException, ServerNotActiveException 
      {
      System.out.println( "Call " + callNumber + " from: " + 
         getClientHost() );
      PrintStream logStream = getLog();
      
      if (logStream == null )
         System.out.println( "Null logger" );
      else   
         logStream.println( "Call " + callNumber + " from: " + 
            getClientHost() );
      setLog( null );          // turns logging off
      
      logStream = getLog();
      if (logStream == null )
         {
         System.out.println( "Null logger" );
         setLog( System.out );
         }
      else
         System.out.println( "You can still log");
         
      return this;
      }

Doc 11, RMI Server Methods Slide # 10
// Server Continued

   public static String RMI_NAME = "cs696/ServerMethods";
   
   public static void main(String args[]) throws RemoteException, IOException
      {
      int port = getPort( args );
      ServerMethodsServer serverObject = new ServerMethodsServer();
      Naming.rebind("//:" + port + "/" + RMI_NAME, serverObject );

      System.out.println("ServerMethodsServer bound in registry");
      }
      
   private static int getPort( String args[] ) throws IOException
      {
      ProgramProperties flags = new ProgramProperties( args );
      int defaultPort = Registry.REGISTRY_PORT;
      int port = flags.getInt( "p", defaultPort );

      return port; 
      }
   }


Command line to Start Server


java -Djava.rmi.server.logCalls=true whitney.rmi.examples.server.ServerMethodsServer -p=7676

Note I am not using the UniVMRegistry

Server Output - Screen

Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:[localhost: sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)]
Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:[localhost: whitney.rmi.examples.server.ServerMethodsServer[0]: whitney.rmi.examples.server.ServerMethods tryMe(int)]
Call 1 from: localhost
Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:Call 1 from: localhost
Null logger
Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:[localhost: whitney.rmi.examples.server.ServerMethodsServer[0]: whitney.rmi.examples.server.ServerMethods tryMe(int)]
Call 2 from: localhost
Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:Call 2 from: localhost
Null logger
Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:[localhost: whitney.rmi.examples.server.ServerMethodsServer[0]: whitney.rmi.examples.server.ServerMethods tryMe(int)]
Call 3 from: localhost
Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:Call 3 from: localhost
Null logger


Doc 11, RMI Server Methods Slide # 11

Server Output - log file


Sun Feb 15 19:17:37 PST 1998:RMI:TCP Accept-1:[localhost: sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)]
Sun Feb 15 19:18:38 PST 1998:RMI:TCP Accept-2:[localhost: sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)]
Sun Feb 15 19:18:38 PST 1998:RMI:TCP Accept-2:[localhost: whitney.rmi.examples.server.ServerMethodsServer[0]: whitney.rmi.examples.server.ServerMethods tryMe(int)]
Sun Feb 15 19:18:38 PST 1998:RMI:TCP Accept-2:Call 1 from: localhost


Doc 11, RMI Server Methods Slide # 12

Snooping on RMI Wire


Source: Robert Penny [rpenny@gensym.com]
Via: Andres Aguiar <aaguiar@GENEXUS.ES>
Warning: I tried this, got a great crash & core dump

Run rmic with the -keepgenerated option, you can change the .java generated files for the stub and the skeleton.

In the skeleton, some of the code looks like this:
java.io.ObjectOutput out = call.getResultStream(true);
out.writeObject($result);

you must add :
java.io.ObjectOutputStream log = 
   new java.io.ObjectOutputStream(
      new java.io.FileOutputStream("return.log", true));

log.writeObject($result);

In the stub the code looks like this:
java.io.ObjectOutput out = call.getOutputStream();
out.writeObject($_arrayOf__Object_1);

you must add :
java.io.ObjectOutputStream log = new
   java.io.ObjectOutputStream(new       
      java.io.FileOutputStream("call.log", true));
log.writeObject($_arrayOf__Object_1);

That creates a file called "call.log" in the client with the serialized parameters, and another one, "return.log" in the server with the serialized return values.

Doc 11, RMI Server Methods Slide # 13

Logging - A More General System


Neil Harrison in Pattern Languages of Program
Design 3 Eds Martin, Riehle, Buschman, 1998, pp 277-289.
sdsu.logging.Logger

Defines types of logging messages
log
debug
warning
error

You can define your own type of logging message

Logging of each type can be turn off, without having to remove the logging statements from code
Different Loggers

ScreenLogger
Send log data to screen

FileLogger
Send log data to a file
NullLogger
Ignores log data


Doc 11, RMI Server Methods Slide # 14
Sample Use of Logger
import sdsu.logging.*;

public class Tester
   {
   public static void main( String[] args) throws 
      LoggerCreationException
      {
      FileLogger myLog = 
         FileLogger.register( "LogFile");

      myLog.debugOff();
      myLog.warningOff();
      
      // Some where else in the program
      
      Logger.debug( "I am lost, This does not work");
      
      Logger.log( "Routine log stuff" );
      }
   }

Doc 11, RMI Server Methods Slide # 15

Remotes without UnicastRemoteObject


There may be times when you want a remote object to have a parent other than UnicastRemoteObject

There are performance reasons for doing this:
Reduce the time for serialization


The following example also shows passing around references to remote objects

This can be done when an object is s child of UnicastRemoteObject


Doc 11, RMI Server Methods Slide # 16

Echo Example

The Players in the Example

Echo
A remote interface

EchoImpl
Implements Echo, but is not child of UnicastRemoteObject

EchoExample
Interface for EchoServer

EchoServer
Server that exports Echo objects

EchoClient
Client that interacts with EchoServer
Client also exports Echo objects
Needs to have rmiregistry running on same machine as client


Doc 11, RMI Server Methods Slide # 17

Remote Echo Interface

package whitney.rmi.examples.server;

import java.rmi.*;

public interface Echo extends Remote 
   {
   public void print( String message ) 
      throws RemoteException;
   }


Doc 11, RMI Server Methods Slide # 18

EchoImpl

package whitney.rmi.examples.server;
import java.rmi.RemoteException;

public class EchoImpl implements Echo
   {
   private static int NEXT_ID = 1;
   
   private int id = NEXT_ID++;
   private String name;
   
   public EchoImpl( String name) 
      {   this.name = name;  }

   public void print( String message  ) throws RemoteException
      {
      System.out.println( "From name: " + name + " " + id + " : " + 
                           message);
      }

   //These are needed to replace UnicastRemoteObject parent
   public int hashCode()
      {   return id;  }
   
   public boolean equals( Object anEcho )
      {
      if ( !(anEcho instanceof  EchoImpl) )
         return false;
      
      if ( id == ((EchoImpl) anEcho).id )
         return true;
      else
         return false;
      }
   
   public String toString()
      {  return "Echo(" + name + "," + id + ")";  }
   }


Doc 11, RMI Server Methods Slide # 19

EchoExample: Server Interface

package whitney.rmi.examples.server;

import java.rmi.RemoteException;

public interface EchoExample extends java.rmi.Remote 
   {
   public Echo getNewEcho( ) throws RemoteException;

   public void setRemoteEcho( Echo fromClient ) 
      throws RemoteException;
   
   public Echo getRemoteEcho() throws RemoteException;
   }


Doc 11, RMI Server Methods Slide # 20

Server Implementation

package whitney.rmi.examples.server;

import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.registry.Registry;
import sdsu.util.ProgramProperties;
import java.io.*;

public class EchoServer 
      extends UnicastRemoteObject
      implements EchoExample
   {
   Echo remoteEcho;
   
   public EchoServer() throws RemoteException {  }

   public Echo getNewEcho( ) throws RemoteException 
      {
      Echo registerFirst = new EchoImpl( "ServerSam");
      registerFirst.print( "In Server.getNewEcho");
      UnicastRemoteObject.exportObject( registerFirst);
      return registerFirst;
      }

   public void setRemoteEcho( Echo fromClient ) 
      throws RemoteException
      {
      remoteEcho = fromClient;
      fromClient.print( "In Server.setRemoteEcho");
      }
   
   public Echo getRemoteEcho() throws RemoteException
      {
      remoteEcho.print( "In Server.getRemoteEcho");
      return remoteEcho;
      }
      
   public static String RMI_NAME = "cs696/EchoServer";
   
   public static void main(String args[]) throws RemoteException, IOException
      {
      int port = getPort( args );
      EchoServer serverObject = new EchoServer();
      Naming.rebind("//:" + port + "/" + RMI_NAME, serverObject );

      System.out.println("EchoServer bound in registry");
      }
      
   private static int getPort( String args[] ) throws IOException
      {
      ProgramProperties flags = new ProgramProperties( args );
      int defaultPort = Registry.REGISTRY_PORT;
      int port = flags.getInt( "p", defaultPort );

      return port; 
      }
   }


Doc 11, RMI Server Methods Slide # 21

Client

package whitney.rmi.examples.server;

import java.rmi.*;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.net.MalformedURLException;
import java.io.IOException;
import sdsu.util.ProgramProperties;
import sdsu.logging.Debug;

public class EchoClient  {
   public static void main(String args[])  {
      try  {
         String serverLabel =    EchoServer.RMI_NAME;
         String server = getServerURL( args, serverLabel );
         
         EchoExample echoServer = 
            (EchoExample) Naming.lookup( server );
         
         Debug.println("First getNewEcho");
         Echo fromServer = echoServer.getNewEcho();
         fromServer.print( "In Client");
         
         Echo clientEcho = new EchoImpl( "ClientClem");
         clientEcho.print( "In Client");

         UnicastRemoteObject.exportObject( clientEcho);

         Debug.println( "First setRemoteEcho");
         echoServer.setRemoteEcho( clientEcho );

         Debug.println( "First getRemoteEcho");
         fromServer = echoServer.getRemoteEcho();
         fromServer.print( "In Client");

         Debug.println( "Done");
         System.exit( 0 );
      } 
      catch ( Exception error)  {  error.printStackTrace(); }
   }

Doc 11, RMI Server Methods Slide # 22
//Client Continued
   
   private static String getServerURL( String args[], 
         String serverLabel ) throws IOException
      {
      String hostKey = "h";
      String portKey = "p";
      
      ProgramProperties flags = new ProgramProperties( args );
      
      String host = null;
      if ( flags.containsKey( hostKey ) )
         host = flags.getString( hostKey );
      else
         {
         System.out.println( "Missing flag " + hostKey );
         System.exit( 0 );
         }
      
      int defaultPort = Registry.REGISTRY_PORT;
      int port = flags.getInt( portKey, defaultPort );
      
      return "rmi://" + host + ":" + port + "/" + serverLabel;
      }
   }


Doc 11, RMI Server Methods Slide # 23

Output


One client was run once
Server Side Output
From name: ServerSam 1 : In Server.getNewEcho
From name: ServerSam 1 : In Client
Client Side Output
Debug server.EchoClient.main(Compiled Code): First getNewEcho
From name: ClientClem 1 : In Client
Debug server.EchoClient.main(Compiled Code): First setRemoteEcho
From name: ClientClem 1 : In Server.setRemoteEcho
Debug server.EchoClient.main(Compiled Code): First getRemoteEcho
From name: ClientClem 1 : In Server.getRemoteEcho
From name: ClientClem 1 : In Client
Debug server.EchoClient.main(Compiled Code): Done

Doc 11, RMI Server Methods Slide # 24

Roaming Remotes- 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 an 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 11, RMI Server Methods Slide # 25


If you really need to know when a client(s) is done with a remote reference it is a good idea to :
have the client explicitly inform the server
catch java.rmi.ConnectException for the cases when the connection goes down
use unreferenced as a back up


visitors since 17-Feb-98