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

Contents of Doc 8, RMI Configuration, API


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

Patterns for Logging Diagnostic Messages, Neil Harrison in Pattern Languages of Program Design 3 Eds. Martin, Riehle, Buschman, 1998, pp. 277-289.

RMI On-line Documentation
Sun HTML Site: http://java.sun.com/products/jdk/1.2/docs/api/overview-summary.html

RMI Source Code
In /opt/jdk1.2/src on rohan.sdsu.edu

Doc 8, RMI Configuration, API Slide # 2

RMI Configuration Problems


There are two problems that occur on rohan due to configuration problems. The first shows when you try to bind the server to the rmiregistry. The second when you try find the server from a client on a remote machine.

Server Binding to rmiregistry


On rohan the following will not bind the server to the rmiregistry

Naming.rebind("rmi://rohan.sdsu.edu:5555/label", serverObject );
Due to some configuration problem, rmi does not think that rohan.sdsu.edu is the local host on rohan.

Use either:

Naming.rebind("rmi://:5555/label", serverObject );

Naming.rebind("rmi://localhost:5555/label", serverObject );

Or see java.rmi.registry.LocateRegistry later in this document

Doc 8, RMI Configuration, API Slide # 3

Client Binding to Remote Server


The situation
Server & rmiregistry run on rohan
Client works fine on rohan
Client can not connect to server from any other machine

The Problem
The server tells rmiregistry it is running on localhost
rmiregistry tells client to look on localhost for the server
Client’s local host does not contain server

Solution

Tell the server its host name by setting the property:

java.rmi.server.hostname

For example:

   java  -Djava.rmi.server.hostname=rohan.sdsu.edu HelloServer &

or
You can set the java.rmi.server.hostname in the properties file for Java or inside your program. If you do it in your program make sure you do it before registering server with RMI Registry. The following code will set the java.rmi.server.hostname property. Make sure you either call it before setting the RMISecurity manager or grant permission to change the property.

void setHostName() {
   Properties systemProperties = 
      new Properties( System.getProperties() );
   systemProperties.put("java.rmi.server.hostname","rohan.sdsu.edu");
   System.setProperties(systemProperties);
}

Doc 8, RMI Configuration, API Slide # 4

What is Supposed to Happen


1. Start RMI

2. Register Server

Server is started on a random port and gives RMI Registry, label, port number and host machine name



Doc 8, RMI Configuration, API Slide # 5
3. Client connects with RMI Registry

RMI Registry gives client server information


4. Client talks to server


Doc 8, RMI Configuration, API Slide # 6

What did Happen?


Server did not know its host name

When Client contacted RMI registry it assumes or is told that the server is on the local host, i.e. the client machine


Client tries to connect to server on its machine, but server is not there!


Doc 8, RMI Configuration, API Slide # 7

Exceptions


All methods in a Remote interface must state they can throw java.rmi.RemoteException

In JDK 1.1.x any exception thrown by a remote method had to be a subclass of RemoteException if you wanted the client to catch the exception. In JDK 1.2 a remote method can throw any exception and the client can catch it. The following example illustrates this.

TestException.java
package whitney.rmi.examples.basic;
public class TestException extends Exception {
   public TestException() {}
   public TestException( String message ) {
      super(message);
   }
}
Hello.java
package whitney.rmi.examples.basic;
import java.rmi.RemoteException;
public interface Hello extends java.rmi.Remote  {
   String sayHello() throws RemoteException, TestException;
}

Doc 8, RMI Configuration, API Slide # 8
HelloServer.java
package whitney.rmi.examples.basic;
import java.io.IOException;
import java.net.InetAddress;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.registry.Registry;      // for port number
import java.rmi.server.UnicastRemoteObject;
import sdsu.util.ProgramProperties;
public class HelloServer 
      extends UnicastRemoteObject
      implements Hello {
   public HelloServer() throws RemoteException { }
   public String sayHello() throws RemoteException, TestException {
      throw new TestException( "this is a test" );
   }
   protected static String getHostName()  {
      try {
         return InetAddress.getLocalHost().getHostName();
      } catch (java.net.UnknownHostException who)  {
         return "Unknown";
      }
   }

Doc 8, RMI Configuration, API Slide # 9
//HelloServer.java Continued
   private static String getHelloHostAddress( String args[] ) 
      throws IOException {
      ProgramProperties flags = 
         new ProgramProperties( args, "config" );
      int defaultPort = Registry.REGISTRY_PORT;
      int port = flags.getInt( "port", defaultPort );
      String serverLabel = flags.getString( "label" );
      // can only bind to local host, protocol defaults
      // to local host, do not add a host here
      return "rmi://" + ":" + port + "/" + serverLabel ;
   }
   public static void main(String args[]){
      System.setSecurityManager(new RMISecurityManager());
      try  {
         String serverAddress = getHelloHostAddress( args );
         HelloServer serverObject = new HelloServer();
         
         Naming.rebind( serverAddress, serverObject);
         System.out.println("HelloServer bound in registry under: " + 
            serverAddress);
      } catch (Exception e)  {
         System.out.println("HelloServer err: ");
         e.printStackTrace();
      }
   }
}

Doc 8, RMI Configuration, API Slide # 10
HelloClient.java
package whitney.rmi.examples.basic;
import java.rmi.*;
import java.rmi.registry.Registry;
import java.net.MalformedURLException;
import java.io.IOException;
import sdsu.util.ProgramProperties;
public class HelloClient {
   public static void main(String args[]) {
      try  {
         String server = getHelloHostAddress( args);
         System.out.println( server );
         Hello remote = (Hello) Naming.lookup( server );
         System.out.println( "after lookup" );
         String message = remote.sayHello();
         System.out.println( message );
      } catch ( TestException test) { 
         System.out.println( "TestException" + test.getMessage() );
         test.printStackTrace();
      } catch ( RemoteException test)  {  
         System.out.println( "RemotException" + test.getMessage() );
         test.printStackTrace(); 
      }
      catch ( Exception test) {  
         System.out.println( "All" + test.getMessage() );
         test.printStackTrace(); 
      }
   }

Doc 8, RMI Configuration, API Slide # 11
//HelloClient.java Continued

   private static String getHelloHostAddress( String args[] ) 
      throws IOException  {
      ProgramProperties flags = 
         new ProgramProperties( args );
      String host = flags.getString( "host" );
      int defaultPort = Registry.REGISTRY_PORT;
      int port = flags.getInt( "port", defaultPort );
      
      String serverLabel = flags.getString( "label" );
      return "rmi://" + host + ":" + port + "/" + serverLabel;
   }
}

Doc 8, RMI Configuration, API Slide # 12

Some Important RMI API

java.rmi.registry.Registry


Methods
bind(String, Remote)
Binds the name to the specified remote object. Throws an exception if name is already used.
list()
Returns an array of the names in the registry.
lookup(String)
Returns the remote object associated with the specified name in the registry.
rebind(String, Remote)
Rebind the name to a new object, replacing any existing binding.
unbind(String)
Unbind the name.

bind, unbind, and rebind work only when used on machine that contains RMI Registry

Static Variables

REGISTRY_PORT Well known port for registry (1099)

Doc 8, RMI Configuration, API Slide # 13

java.rmi.registry.LocateRegistry

Static Methods

createRegistry(int)
Create and export a registry on the local host.
createRegistry(int port,
RMIClientSocketFactory cf,
RMIServerSocketFactory sf)
Creates and exports a Registry on the local host that uses custom socket factories for communication with that registry
getRegistry()
Returns the remote object Registry for the local host.
getRegistry(int)
Returns the remote object Registry on the current host at the specified port.
getRegistry(String)
Returns the remote object Registry on the specified host at a default (i.e., well-known) port number.
getRegistry(String, int)
Returns the remote object Registry on the specified host at the specified port.
getRegistry(String host,
int port,
RMIClientSocketFactory cf)
Returns the remote object Registry on the specified host and port. Uses the factory to create sockets used to connect to Registry.

The methods in Naming.bind perform two basic functions:
Parse the URL
Call the proper Registry methods

You can use LocateRegistry & Registry to replace the usage of Naming.

Doc 8, RMI Configuration, API Slide # 14
Server Side usage of LocateRegistry
This example shows how to create a registry and bind server objects in one method and one JVM.
package whitney.rmi.examples.basic;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import sdsu.util.ProgramProperties;
public class HelloServer 
      extends UnicastRemoteObject
      implements Hello {
   public HelloServer() throws RemoteException { }
   public String sayHello() throws RemoteException {
      return  "Hello World from " + getHostName();
   }
   private static Registry getRegistry( int port ) throws RemoteException {
      try {
         return LocateRegistry.createRegistry(port );
      } catch (Exception noRegistry) {
         return LocateRegistry.getRegistry( port );
      }
   }
   public static void main(String args[]) {
      System.setSecurityManager(new RMISecurityManager());
      try {
         ProgramProperties flags =
            new ProgramProperties( args, "config" );
         int port = flags.getInt( "port", Registry.REGISTRY_PORT);
         String serverLabel = flags.getString( "label" );
         HelloServer serverObject = new HelloServer();
         Registry myRegistry = getRegistry(port );
         myRegistry.rebind( serverLabel, serverObject);
         System.out.println("HelloServer bound as: " + serverLabel);
      } catch (Exception e) {
         System.out.println("HelloServer err: ");
         e.printStackTrace();
      }
   }
}

Doc 8, RMI Configuration, API Slide # 15
Client-Side usage of LocateRegistry

public class HelloClient  
   {
   public static void main(String args[])  
      {
      try  
         {
         Registry local = 
            LocateRegistry.getRegistry("eli.sdsu.edu", 1099 );
         Hello remote = (Hello) local.lookup( "test" );
         String message = remote.sayHello();
         System.out.println( message );
         } 
      catch ( Exception test) 
         {  
         System.out.println( "All" + test.getMessage() );
         test.printStackTrace(); 
         }
      }

Doc 8, RMI Configuration, API Slide # 16

Server Parent Classes


Servers typically extend UnicastRemoteObject:

public class HelloServer 
      extends UnicastRemoteObject
      implements Hello { blah}
The class Structure

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


Doc 8, RMI Configuration, API Slide # 17

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
getRef()
Returns the remote reference for the 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
toStub(Remote obj)
Returns the stub for the remote object obj passed as a parameter.

Sample output of toString() on a RemoteObject object

whitney.rmi.examples.basic.HelloServer_Stub[RemoteStub [ref: [endpoint:[130.191.234.12:33880](remote),objID:[1ad7c0b:d5fefc4e28:-8000, 0]]]]


Doc 8, RMI Configuration, API Slide # 18

java.rmi.server.RemoteServer


Static Methods
getClientHost()
Return the hostname of the current client.

setLog(OutputStream out)
Log RMI calls to the output stream out. If out is null, call logging is turned off.
PrintStream getLog()
Returns stream for the RMI call log.

To use logging on the server, you need to set to true the System property:

   java.rmi.server.logCalls

Doc 8, RMI Configuration, API Slide # 19

Logging Example

package whitney.rmi.examples.basic;
import java.io.IOException;
import java.io.PrintStream;
import java.io.FileOutputStream;
import java.io.BufferedOutputStream;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.RemoteServer;
import java.rmi.server.ServerNotActiveException;
public class HelloServer 
      extends UnicastRemoteObject
      implements Hello {
   PrintStream logger; 
   public HelloServer() throws RemoteException {
      try {
         FileOutputStream log = new FileOutputStream( "MyLog");
         setLog(new BufferedOutputStream( log ));
         logger = getLog();
      } catch(java.io.FileNotFoundException noFile ) {
         logger = null; 
         System.err.println( "No log file" );
      }
   }
   public String sayHello() throws RemoteException  {
      try {
         if (logger != null )
         logger.println( "sayHello called by: " + 
            RemoteServer.getClientHost() );
      } catch (ServerNotActiveException error ) {
         logger.println( "sayHello called, can not get client host" );
      }
      return  "Hello World from eli"; 
   }
}

Doc 8, RMI Configuration, API Slide # 20
Starting the Server
The following command was used to start the server:

java -Djava.rmi.server.logCalls=true whitney.rmi.examples.basic.HelloServer &

Log Contents

The following are the contents of log file. These entries were generated by one client request. Note that the call to RemoteServer.getClientHost was not needed as the log entry already contained the client IP address.

Mon Feb 15 17:09:45 PST 1999:RMI:RMI TCP Connection(3)-eli.sdsu.edu/130.191.234.12:[130.191.234.12: sun.rmi.registry.RegistryImpl[0:0:0, 0]: java.rmi.Remote lookup(java.lang.String)]
Mon Feb 15 17:09:46 PST 1999:RMI:RMI TCP Connection(4)-eli.sdsu.edu/130.191.234.12:[130.191.234.12: sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)]
Mon Feb 15 17:09:47 PST 1999:RMI:RMI TCP Connection(4)-eli.sdsu.edu/130.191.234.12:[130.191.234.12: whitney.rmi.examples.basic.HelloServer[0]: public abstract java.lang.String whitney.rmi.examples.basic.Hello.sayHello() throws java.rmi.RemoteException]
Mon Feb 15 17:09:47 PST 1999:RMI:RMI TCP Connection(4)-eli.sdsu.edu/130.191.234.12:sayHello called by: 130.191.234.12

Doc 8, RMI Configuration, API Slide # 21

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 8, RMI Configuration, API Slide # 22
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 8, RMI Configuration, API Slide # 23

java.rmi.server.UnicastRemoteObject


Constructors
UnicastRemoteObject()
Create & export a UnicastRemoteObject object using an anonymous port.
UnicastRemoteObject(int port)
Create & export an UnicastRemoteObject object using the particular supplied port.
UnicastRemoteObject(int port,
RMIClientSocketFactory cf,
RMIServerSocketFactory sf)
Create & export an UnicastRemoteObject object using the particular supplied port and socket factories
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.
All the above methods are static except clone();
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 16-Feb-99    Next