RMIClient/ RMIServer
jlouie 4.97
jdk1.1 release/ Win95/NT


INTRODUCTION:

A test of the java.rmi (remote method invocation) API.
This archive contains source code for a command line RMIServer and
GUI RMIClient demonstrating RMI, POLYMORPHISM and ACTIVE NOTIFICATION.


ACTIVE NOTIFICATION:

This package contains a BroadcasterInterface and a ListenerInterface.
The listener implements the ListenerInterface and registers itself
with a broadcaster. The broadcaster implements the BroadcasterInterface and
passes a reference to itself back to the listener. The broadcaster can
return a message string or vector of objects back to the listener by
implementing getMessage and getVector.


POLYMORPHISM and TYPE:

Classically, type is a compile time notion such that references have type
and objects have class. However, Java supports the concept of interfaces.
Although, Java does not support multiple inheritence of classes, it does
support mulitple inheritence of interfaces. It may be helpful, then, to consider
"type" to be a "name of an interface."* Under this definition, an object can
be of one or more types. In this design, two objects Administrator and 
Anonymous both implement a common interface. The objects are of the "type"
ClientInterface. One passes a reference of type ClientInterface back to the
client. The client does not need to be aware of the class of the object, only
that the object implements the ClientInterface. Depending on the actual
class of the object, the objects may respond differently to a method invocation
since they may implement the methods in a unique way (eg. they may be of more
than one form -- polymorphism).

* For a full discussion of this concept see "Design Patterns" by Gamma et al.
pg. 13.

INHERITANCE

It can become a chore to implement all of the methods of the WindowListener
interface. Instead, one can create a subclass of Frame (WFrame) with empty
implementations of WindowListener. One can then use inheritance to extend
WFrame. RMIClient extends WFrame for this reason.

REMOTE METHOD INVOCATION

In a nutshell, one creates a class (eg. RMIConnection) that
extends UnicastRemoteObject and implements an interface
(eg. RMIConnectionInterface). The interface, in turn extends
java.rmi.Remote. One then creates an instance of the remote object
and binds it to a name:

Naming.rebind("TestConnection", connection));

The client "looks up" the remote object using the rmiregistry:

Object o= Naming.lookup("//"+hostName+"/TestConnection")); 

One can cast the reference of type Object
to a reference of the appropriate interface type 
(eg. RMIConnectionInterface). The client can then invoke methods
on the remote object using the reference. Normally there is only one
remote object that is referenced by multiple clients.

DESIGN CONSIDERATIONS:

In this example, one creates three remote server objects: RMIConnection,
Administrator and Anonymous. When the client connects, it is passed
a reference which can be cast to the type RMIConnectionInterface.

The client can log onto the server as an Administrator or as
a Anonymous client. The client is returned a reference to an object.
The object is of "type" ClientInterface. The reference of type Object can be cast
to the type ClientInterface. The actual object may be of class
Administrator or class Anonymous.
 
The Administrator can set passwords. The client
cannot set passwords. This is done using POLYMORPHISM as both the
Administrator and the Anonymous class implement the
ClientInterface in a markedly different manner. 

Mentally one can divide the instance methods into those which can be
called remotely(eg. setMyPassword) and those which can only be called locally
(eg. setInternalPassword).

The RMIServer class implements the ListenerInterface. The RMIConnection
class implements the BroadcasterInterface. This allows
the RMIConnection object to notify the RMIServer when a client
fails/succeeds in logging on. One registers the RMIServer
object with the RMIConnection object. The RMIConnection object
(the broadcaster) can then ACTIVELY NOTIFY the RMIServer (a listener)
when the state of the broadcaster has changed. A similar approach is
used with RMIClient and the LogOn class.

COMPILING and EXECUTING the CODE:

To compile this code, place the source code in a folder named
src and place the src folder in the bin folder.
Compile the exceptions from the bin level:
c:\jdk1.1\bin>javac -d . .\src\exceptions\*.java

Then compile the interfaces:
c:\jdk1.1\bin>javac -d . .\src\interfaces\*.java

Then compile the remaining code:
c:\jdk1.1\bin>javac -d . .\src\*.java

Then compile the stubs and skeletons:
c:\jdk1.1\bin>rmic -d . jlouie.rmi.RMIConnection
c:\jdk1.1\bin>rmic -d . jlouie.rmi.Administrator
c:\jdk1.1\bin>rmic -d . jlouie.rmi.Anonymous

These stubs are downloaded to the client as act as proxies
for the remote objects on the client.

Be sure to set your classpath correctly.
eg:SET CLASSPATH= .;C:\JDK1.1;C:\JDK1.1\bin;C:JDK1.1\lib\classes.zip

To test the compiled bytecode on a single machine:

Run the rmiregistry:
c:\jdk1.1\bin>start rmiregistry

Run the server:
c:\jdk1.1\bin>java RMIServer

Run the client:
c:\jdk1.1\bin>java RMIClient

Here is the command line syntax for a network connection:
java RMIServer [connectionName]
java RMICLient [connectionName] [host]

Default is "TestConnection", localhost.

On Win95, the OS may try to make a modem connection. Just cancel.

Hoping this is making some sense,
Jeff
