You are on page 1of 145

Client/ Server

Chap. 4: Java RMIRemote Method


Invocation

dbc@csit.fsu.edu

Remote Method Invocation

Java RMI is a mechanism that allows a Java program running on


one computer (e.g., the client) to apply a method to an object on
a different computer (e.g., the server).
In itself, the syntax of the remote invocation looks exactly like an
ordinary Java method invocation. The remote method call can be
passed arguments computed in the context of the local machine.
It can return arbitrary values computed in the context of the
remote machine. The RMI system transparently forwards these
arguments and results.
RMI is an implementation of the of the Distributed Object
programming modelsimilar to CORBA, but simpler, and
specialized to the Java language

dbc@csit.fsu.edu

Example

Assume code running in the local machine holds a remote


reference to an object obj on a remote machine:

obj
res = obj.meth(arg) ;

ResType meth(ArgType arg) {


...
return new ResImpl(. . .) ;
}

Local Machine
Remote Machine
dbc@csit.fsu.edu

Central Components of Java RMI

Remote objectsthese are normal Java objects, but their class


extends some RMI library class that incorporates support for
remote invocation.
Remote referencesobject references that effectively refer to
remote objects, typically on a different computer.
Remote interfacesnormal Java interfaces, that specify the
API of a remote object. They should extend the marker
interface, java.rmi.Remote. The remote interface must be
known to both the local and remote code.

dbc@csit.fsu.edu

Some Supporting Technologies

Registriesplaces where the local machine initially looks to


find a reference to a remote object.
Serializationreduction of Java objects to a representation
that can be communicated as a byte stream (for arguments and
results).
Dynamic class loadingneeded in various places. One
example is when a remote method returns an object whose
class (e.g. ResImpl) was not previously known on the calling
machine. Also used for stubssee later.
Security managerused to control the behavior of code
loaded from a remote host.

dbc@csit.fsu.edu

Related Approaches to Networking

Sockets
Traditionally quite hard to program, although the java.net package
makes it relatively easy to establish a socket network connection to
another host. Communication takes place via streams, but you must
define the detailed protocols for message exchange yourself.
High-level compared with Unix sockets, but low-level compared to
RMI.

Remote Procedure Call (RPC)


An earlier UNIX protocol to allow calling remote procedures.
Programmers register their application with a host port mapper.
Protocols for parameter-passing support a limited number of types.

CORBA
See next semesters course. . .

dbc@csit.fsu.edu

References
Core

Java 2, Volume II, Chapter 5: Remote Objects.


Java RMI, Troy Bryan Downing, IDG books, 1998.
Getting Started Using RMI, and other documents, at:
http://java.sun.com/products/jdk/rmi/

dbc@csit.fsu.edu

Getting Started

dbc@csit.fsu.edu

The Remote Interface

In RMI, a common remote interface is the minimum amount


of information that must be shared in advance between
client and server machines. It defines a high-level
protocol through which the machines will communicate.
A remote interface is an ordinary Java interface, which must
extent the marker interface java.rmi.Remote.
All methods in a remote interface must be declared to throw
the java.rmi.RemoteException exception.

dbc@csit.fsu.edu

A Simple Example

A file MessageWriter.java contains the interface definition:


import java.rmi.* ;
public interface MessageWriter extends Remote {
void writeMessage(String s) throws RemoteException ;
}

This interface defines a single remote method,


writeMessage().

dbc@csit.fsu.edu

10

java.rmi.Remote

The interface java.rmi.Remote is a marker interface.


It declares no methods or fields; however, extending it tells
the RMI system to treat the interface concerned as a remote
interface.
In particular we will see that the rmic compiler generates
extra code for classes that implement remote interfaces. This
code allows their methods to be called remotely.

dbc@csit.fsu.edu

11

java.rmi.RemoteException

Requiring all remote methods be declared to throw


RemoteException was a philosophical choice by the
designers of RMI.
RMI makes remote invocations look syntactically like local
invocation. In practice, though, it cannot defend from
problems unique to distributed computingunexpected
failure of the network or remote machine.
Forcing the programmer to handle remote exceptions helps to
encourage thinking about how these partial failures should be
dealt with.
See the influential essay: A Note on Distributed Computing
by Waldo et al, republished in The Jini Specification:
http://java.sun.com/docs/books/jini

dbc@csit.fsu.edu

12

The Remote Object

A remote object is an instance of a class that implements a


remote interface.
Most often this class also extends the library class
java.rmi.server.UnicastRemoteObject. This class includes
a constructor that exports the object to the RMI system when
it is created, thus making the object visible to the outside
world.
Usually you will not have to deal with this class explicitly
your remote object classes just have to extend it.
One fairly common convention is to name the class of the
remote object after the name of the remote interface it
implements, but append Impl to the end.

dbc@csit.fsu.edu

13

A Remote Object Implementation Class

The file MessageWriterImpl.java contains the class declaration:


import java.rmi.* ;
import java.rmi.server.* ;
public class MessageWriterImpl extends UnicastRemoteObject
implements MessageWriter {
public MessageWriterImpl() throws RemoteException {
}
public void writeMessage(String s) throws RemoteException {
System.out.println(s) ;
}
}

dbc@csit.fsu.edu

14

Remarks

The constructor MessageWriterImpl() has an empty body.


But recall that if there is no explicit constructor invocation in
the body of a subclass constructor, it implicitly invokes
super().
Hence the vital constructor of UnicastRemoteObject is
called.
This constructor is declared to throw RemoteException. The
MessageWriterImpl() constructor must be declared to throw
this exception in turn, otherwise there will be a compiler error
message.
Of course the class must also define all the methods of the
remote interface MessageWriter, which it implements.

dbc@csit.fsu.edu

15

Compiling the Remote Object Class

To compile classes that implement Remote, you must use the


rmic compiler. The reasons will be discussed later. For
example:
sirah$ rmic MessageWriterImpl

dbc@csit.fsu.edu

16

Client and Server Programs

We have completed the Java files for the remote object class
itself, but we still need the actual client and server programs
that use this class.
In general there are some pieces of administrivia one has to
deal withpublishing class files and installing security
managers.
To minimize distractions, we initially make the simplifying
assumption that both client and server have copies of all class
files for MessageWriter (e.g., they may share access through
shared NFS directories).
Then we also dont need a security manager, because all code
is local, and therefore trusted.

dbc@csit.fsu.edu

17

A Server Program

We assume the file HelloServer.java contains the class


declaration:
import java.rmi.* ;
public class HelloServer {
public static void main(String [] args) throws Exception {
MessageWriter server = new MessageWriterImpl() ;
Naming.rebind(messageservice, server) ;
}
}

dbc@csit.fsu.edu

18

Remarks

To avoid cluttering this illustrative code with try-catch


statements, we simply have the main() method throw all
exceptions (not good practice in general).
This program does two things:
It creates a remote object with local name server.
It publishes a remote reference to that object with external
name MessageWriter.
The call to Naming.rebind() places a reference to server in
an RMI registry running on the local host (i.e., the host where
the HelloServer program is run).
Client programs can obtain a reference to the remote object by
looking it up in this registry.
dbc@csit.fsu.edu

19

A Client Program

We assume the file HelloClient.java contains the class


declaration:
import java.rmi.* ;
public class HelloClient {
public static void main(String [] args) throws Exception {
MessageWriter server =
(MessageWriter) Naming.lookup(
rmi://sirah.csit.fsu.edu/messageservice) ;
server.writeMessage(Hello, other world) ;
}
}

dbc@csit.fsu.edu

20

Remarks

Again the program does two things:


It looks up a reference to a remote object with external
name MessageWriter, and stores the returned reference
with local name server.
Finally (!), it invokes the remote method, writeMessage(),
on server.
The call to Naming.lookup() searches in a remote RMI
registry. Its argument is a URL, with protocol tag rmi.
This example assumes the remote object lives on the host
sirah, and has been registered in the default RMI registry
(which happens to listen on port 1099) on that machine.

dbc@csit.fsu.edu

21

Compiling and Running the Example

Compile HelloServer and HelloClient on their respective


hosts, e.g.:
sirah$ javac HelloServer
merlot$ javac HelloClient

Either ensure client and server share the current directory, or


copy all files with names of the form MessageWriter * .class
to the clients current directory.

Then. . .

dbc@csit.fsu.edu

22

Running HelloClient/HelloServer

dbc@csit.fsu.edu

23

Running HelloClient/HelloServer

dbc@csit.fsu.edu

24

Running HelloClient/HelloServer

dbc@csit.fsu.edu

25

Running HelloClient/HelloServer

dbc@csit.fsu.edu

26

Running HelloClient/HelloServer

dbc@csit.fsu.edu

27

Remark on Using the RMI Registry

In this example we ran the RMI registry on its default port.


In general this is probably a bad idea, especially if the server is used
by many people, because there is no mechanism to prevent
interference.
It is better to start a registry a non-default port number of your own
choice, e.g.:
sirah$ rmiregistry 4956 &

The Naming calls become, e.g.:


Naming.rebind(rmi://sirah.csit.fsu.edu:4956/messageservice, server) ;
Naming.lookup(rmi://sirah.csit.fsu.edu:4956/messageservice) ;

dbc@csit.fsu.edu

28

The Mechanics of Remote Method


Invocation

dbc@csit.fsu.edu

29

Is RMI a Language Extension?

Invocation of a method on a remote object reproduces the


look and feel of local invocation amazingly well.
Yet the internal mechanics of remote invocation are much
more complex than local invocation:
Argumentswhich may be objects of arbitrary complexityare
somehow collected together into messages suitable for shipping across
the Internet.
Results (or exceptions) are similarly shipped back.

Perhaps surprisingly, RMI involves essentially no


fundamental modification to the Java language, compiler, or
virtual machine.
The illusion of remote invocation is achieved by clever
libraries, plus one relatively simple post-processor tool
(rmic).
dbc@csit.fsu.edu

30

Exchanging Remote References

A good feature of RMI is that references to other remote


objects can be passed as arguments to, and returned as results
from, remote methods.
Starting with one remote object reference (presumably
obtained from an RMI registry) a client can, for example,
obtain references to additional remote objectsreturned by
methods on the first one.

dbc@csit.fsu.edu

31

Example: a Printer Directory

Perhaps more relevant on LAN than the Internet, but it


illustrates the idea:
public interface Printer extends Remote {
void print(String document) throws RemoteException ;
}
public interface PrinterHub extends Remote {
Printer getPrinter(int dpi, boolean isColor)
throws RemoteException ;
}

A client might initially obtain a PrinterHub reference from


the RMI registry. The remote object contains some table of
printers on the network.
An individual Printer interface is returned to the client,
according to specifications given in getPrinter().
dbc@csit.fsu.edu

32

Remote References have Interface Type

This is a powerful feature, but there is one interesting


restriction:
If a particular argument or result of a remote method itself
implements Remote, the type appearing in the method
declaration must be a remote interface. The declared type
cannot be a remote implementation class.

We have also seen earlier that the remote object reference


returned by Naming.lookup() can be cast to the expected
remote interface type.
However, this reference cannot be cast it to the
implementation class of the remote object! A
ClassCastException will occur if you try.

dbc@csit.fsu.edu

33

Stubs

What this tells us is that, however they are obtainedand


however they lookremote references are not, in reality, Java
references to remote objects. They are Java references to
local objects that happen to implement the same remote
interfaces as the remote objects concerned.

The local Java object referenced is actually an instance of a


stub class.

dbc@csit.fsu.edu

34

Some Important Parts of RMI

Stubs.
Each remote object class has an associated stub class, which
implements the same remote interfaces. An instance of the stub class
is needed on each client. Client-side remote invocations are actually
local invocations on the stub class.

Serialization.
Arguments and results have to be marshaledconverted to a
representation that can be sent over the Net. In general this is a highly
non-trivial transformation for Java objects. Serialization is also used
for distributing stubs.

The Server-side Run-time System.


This is responsible for listening for invocation requests on suitable IP
ports, and dispatching them to the proper, locally resident remote
object.

dbc@csit.fsu.edu

35

Architecture
Internet

Client

Call stub method


locally

Client
Code

Call remote object


method locally

Send marshaled
arguments

Stub

Return value
or throw exception

Server

Send marshaled
result or
exception

RMI
Run-time
System

dbc@csit.fsu.edu

Remote
Object

Return value
or throw exception
36

The Role of rmic

The only compiler technology peculiar to RMI is the rmic


stub generator.
The input to rmic is a remote implementation class, compiled
in the normal way with javac (for example).
The stub generator outputs a new class that implements the
same remote interfaces as the input class.
The methods of the new class contain code to send arguments
to, and receive results from, a remote object, whose Internet
address is stored in the stub instance.

dbc@csit.fsu.edu

37

Example Operation of rmic

An earlier example of a remote implementation class:


public class MessageWriterImpl extends UnicastRemoteObject
implements MessageWriter {
...
public void writeMessage(String s) throws RemoteException {
...
}
}

We issue the command:


rmic v1.2 keep MessageWriterImpl
The flag v1.2 avoids generation of unnecessary code, needed only for
backward compatibility (including skeleton classes).
The flag keep causes the intermediate Java source to be retained.

Output files will be MessageWriterImpl_Stub.java and


MessageWriterImpl_Stub.class.
dbc@csit.fsu.edu

38

The Generated Stub Class


public final class MessageWriterImpl_Stub
extends java.rmi.server.RemoteStub
implements MessageWriter, java.rmi.Remote {
...
public MessageWriterImpl_Stub(java.rmi.server.RemoteRef ref) {
super(ref);
}
public void writeMessage(java.lang.String $param_String_1)
throws java.rmi.RemoteException {
try {
ref.invoke(this, $method_writeMessage_0,
new java.lang.Object[] {$param_String_1},
4572190098528430103L);
} ...
}
}
dbc@csit.fsu.edu

39

Remarks on the Stub Class

The stub class includes an inherited field ref, of type


RemoteRef.
Essentially the stub class is just a wrapper for this remote
reference.
Remote methods are dispatched through the invoke() method
on ref.
This is passed an array of Objects holding the original
arguments (in general it also returns an Object).
It is also passed arguments to identify the particular method to
be invoked on the server.
Essentially the stub wrapper is providing compile-time type
safety. The actual work is done in library classes that dont
know the compile-time type in advance.
dbc@csit.fsu.edu

40

Marshalling of Arguments

Objects passed as arguments to invoke() must be marshaled


for transmission over the network.
The representation of a Java object inside the Java Virtual
Machine is complex:
An object includes references to all its fields, which may themselves
be objects. These may in turn reference other objects.
An object will reference its class object, which contains runtime
information about the objects type.

This internal representation is also not standardizeddifferent


vendors implementation of the JVM will certainly use
different representations.
If objects are to be exchanged between JVMs, we need a
standardized way to encode all the information.
dbc@csit.fsu.edu

41

Object Serialization

Java has a general framework for converting objects (and


groups of objects) to an external representation that can later
be read back into an arbitrary JVM.
This framework is called Object Serialization.
Object serialization is very important to RMI, but it has other
applications as well.
For example, a running program can use object serialization to
dump the current state of a particular object to a file. Much
later, another program can read the file and reincarnate an
exact replica of the original object. This is a mechanism for
object persistence.

dbc@csit.fsu.edu

42

I/O Streams

The technology for serializing and deserializing objects is


found in a pair of the many I/O stream classes of Java.
In general an output stream (for example) can be associated
with various targets:
a file, an Internet socket connection, an internal Java array of bytes to
which one is writing externally formatted data, etc.

The abstract superclass OutputStream provides low-level


write methods like:
public void write(byte [] buffer) throws IOException {. . .}

Subclasses may override the implementation for a particular


output target.
Subclasses may also add extra methods that take more general
data, convert them to a byte array, then invoke write() to do the
final output.
dbc@csit.fsu.edu

43

Object Streams

ObjectOutputStream is a subclass that adds methods


including:
public void writeInt(int val) throws IOException {. . .}
public void writeFloat(float val) throws IOException {. . .}

etc, and most interestingly:


public void writeObject(Object obj) throws IOException, . . . {. . .}

Similarly ObjectInputStream extends InputStream and adds:


public int readInt() throws IOException {. . .}

etc, and:
public Object readObject() throws IOException, . . . {. . .}

dbc@csit.fsu.edu

44

Using Object Streams

We can use the writeObject() method of an


ObjectOutputStream to write an object to a file, an Internet
socket connection, etc.
Later we use the readObject() method of an
ObjectInputStream to read an object from the same file, the
other end of the socket connection, etc.
When deserialization occurs, a new object is created in the
second JVM. As far as possible this is a perfect replica of the
the original object.

dbc@csit.fsu.edu

45

Serialization Preserves Object Graphs

Consider this binary tree node class:


class Node implements Serializable {
Node() {}
Node(Node left, Node right) {
this.left = left ;
this.right = right ;
}
private Node left, right ;
}

We create a small tree, d, by:


Node a = new Node(), b = new Node() ; // Leaves
Node c = new Node(a, b) ;
Node d = new Node(c, null) ;
dbc@csit.fsu.edu

46

Serializing and Deserializing a Tree


a

Write out the root of the tree:


out.writeObject(d) ;

c
d
a

Read a node later by:


Node e = (Node) in.readObject() ;

b
c
e

The whole of the original tree is reproduced. Copies a,


b, c of the original sub-nodes are recreated along with e.
The pattern of references is preserved.
dbc@csit.fsu.edu

47

Referential Integrity is Preserved

This behavior is not limited to


trees.

In this example both b and c


reference a single object a.
Again the pattern of links is
preserved. When the root object is
reconstructed from its serialized
form, a single a, referenced twice,
is also created.
Generally referential integrity is
preserved amongst all objects
written to a single
ObjectOutputStream.
dbc@csit.fsu.edu

b
d

a
c

b
e

48

The Serializable Interface

Serializable is another marker interface. An objects class


must implement Serializable if it is to be passed to
writeObject(). If it doesnt, a NotSerializableException will
be thrown.
Implementing Serializable doesnt appear to affect the way
the Java compiler and JVM treat the class in generalit
seems to be simply a safety feature in ObjectOutputStream.

dbc@csit.fsu.edu

49

Argument Passing in RMI

In general any object-valued argument or result of a remote


method must either implement Remote or Serializable.

If the argument or result implements Remote, it is effectively


passed by (remote) reference.

If it implements Serializable, it is passed by serialization and


copying. Referential integrity is preserved within the limits of
the arguments of a single invocation, as described above.

dbc@csit.fsu.edu

50

Passing by Remote Reference

The serialization stream used by RemoteRef.invoke() is


actually a subclass of ObjectOutputStream, which has been
customized to make certain substitutions in the output stream.
In particular this stream recognizes the class of a remote
object passed to it, and if necessary replaces it with a
RemoteStub object in the output stream.
It gets the stub from an implementation class using the
RemoteObject.toStub().

So even if a remote object implementation is passed as an


argument (by the host that holds the object), what will be
received is a stub.
Stub classes themselves implement Serializable. So once
references have been converted to stubs, they just get passed
from host to host by value.
dbc@csit.fsu.edu

51

Argument Passing Examples

To end this section we work through two examples that are


interesting in their own right, and also demonstrate the two
fundamental ways of passing arguments in RMI.

dbc@csit.fsu.edu

52

Example: a File Reading Service

The earlier Hello example involved a very trivial remote


I/O service, whereby a client could write a string to the
console of a server.
Here we generalize to a more useful service that reads a file
on the server and returns its contents to a client.
In particular it will illustrate how RMI implicitly uses
serialization for a java.util class, returned as a remote method
result.

dbc@csit.fsu.edu

53

The Remote Interface

The file FileSource.java:


import java.util.* ;
import java.io.* ;
import java.rmi.* ;
public interface FileSource extends Remote {
public Vector readFile(String File)
throws RemoteException, IOException ;
}

dbc@csit.fsu.edu

54

The Remote Object Implementation

The definition of FileSourceImpl:


public class FileSourceImpl extends UnicastRemoteObject
implements FileSource {
public FileSourceImpl() throws RemoteException {}
public Vector readFile(String file)
throws RemoteException, IOException {
Vector lines = new Vector() ;
BufferReader in = new BufferReader(new FileReader(file)) ;
while(true) {
String line = in.readLine() ;
if(line == null) break ;
lines.addElement(line) ;
}
return lines ;
}
}
dbc@csit.fsu.edu

55

The Server Program

The definition of the class FileServer:


public class FileServer {
public static void main(String [] args) throws Exception {
FileSource server = new FileSourceImpl() ;
Naming.rebind(
rmi://sirah.csit.fsu.edu:4965/fileservice, server) ;
}
}

(We chose the registry port as a random number between 1024


and 64K.)

dbc@csit.fsu.edu

56

The Client Program

The definition of the class FileClient:


public class FileClient {
public static void main(String [] args) throws Exception {
FileSource server = (FileSource) Naming.lookup(
rmi://sirah.csit.fsu.edu:4965/fileservice) ;
Vector lines = server.readFile(students) ;
// The remote invocation
for(int i = 0 ; i < lines.size() ; i++)
System.out.println((String) lines.get()) ;
}
}

dbc@csit.fsu.edu

57

Compiling

On the server:
rmic FileSourceImpl
javac FileServer
(Note rmic will automatically invoke javac if FileSourceImpl.java
has not previous been compiled. javac, in turn, will notice a
dependency on FileSource.java, and compile that file if necessary.)

Copy the files FileSource.class and


FileSourceImpl_Stub.class from server to client.
Later we will see how to use dynamic class loading to avoid copying
the stub class to the client manually.

On the client:
javac FileClient

dbc@csit.fsu.edu

58

Running FileClient/FileServer

dbc@csit.fsu.edu

59

Running FileClient/FileServer

dbc@csit.fsu.edu

60

Remarks

The file students lives on the server. It is not directly


accessible to the client.
The FileSource object reads the file, and saves its lines in a
Vector.
The Vector is returned as a result of the remote method
readFile(). Vector, and the String class of the included
elements, both implement Serializable. The return value is
transparently serialized in the server and deserialized on the
client.
We could also have used an array of String objectsan array
type is serializable if its component type is.

dbc@csit.fsu.edu

61

Example: The RMI Registry

The RMI registry is a process that normally runs on the


server.
At first sight the registry seems to have a privileged role in
RMI. Actually it is just another remote object.

dbc@csit.fsu.edu

62

The RMI Registry

Client

Server

Request
Reference
Client
Code

Registry Store
Reference
Remote
Object

dbc@csit.fsu.edu

63

The Registry Remote Interface

Instead of interacting with the registry indirectly through the


Naming class, it is possible to obtain a direct remote
reference to the registry object.
Its remote interface is defined in the package
java.rmi.registry. The interface includes:
public interface Registry extends Remote {
public Remote lookup(String name) throws . . . ;
public bind(String name, Remote obj) throws . . . ;
public rebind(String name, Remote obj) throws . . . ;
...
}

dbc@csit.fsu.edu

64

The LocateRegistry Class

This class constructs a stub for an existing Registry object.


(It can also create a new registry implementation object,
running in the current JVM.)
The interface includes:
public final class LocateRegistry {
public static Registry getRegistry(String host, int port)
throws . . . {. . .}
public static Registry createRegistry(int port)
throws . . . {. . .}
...
}

dbc@csit.fsu.edu

65

Using the Registry Interface Directly

An alternative definition of the class FileServer:


public class FileServer {
public static void main(String [] args) throws Exception {
FileSource server = new FileSourceImpl() ;
Registry reg =
LocateRegistry.getRegistry(sirah.csit.fsu.edu, 4965) ;
reg.rebind(fileservice, server) ;
//A remote method invocation
}
}

We are particularly interested in this example because it


involves passing a remote object implementation, server, as an
argument to a remote method, rebind().
dbc@csit.fsu.edu

66

Passing a Remote Object Argument

The server argument of rebind() is a true Java reference to a


remote object implementation.
When the invoke() call is made (on the remote reference
embedded in reg) it uses a customized object-stream class. As
mentioned earlier, this tests for instances of remote objects
among the arguments, and treats them specially.
In the output stream, it will replace the implementation object
with a stub obtained by applying the RemoteObject.toStub()
method to server.
Thus the registry receives a stub.
This is a general mechanism that applies whenever a locally
resident remote object is passed as an argument to a remote
method.
dbc@csit.fsu.edu

67

Summary

In principle most of the features that have been discussed in


this section are hidden inside the implementation of RMI. In
an ideal world you would not have to know about them.
In practice, to successfully deploy an RMI-based application,
you will probably need to at least be aware of some
fundamental issues.
You need to be aware of the existence of stub objects, and the
basic working of object serialization.
You should be aware that references to remote objects are
normally produced by creating a stub object on the server,
then passing this stub to registry and clients in serialized form.

dbc@csit.fsu.edu

68

Dynamic Class Loading

dbc@csit.fsu.edu

69

Byte Code Instructions for Stubs?

As we have seen: before any client can use an RMI remote


object, it must receive a serialized stub object.
The serialized stub contains a remote reference. Data fields of
the reference may include information like:
The name of the host where the remote object lives,
Some port number on that host, where the RMI run-time system is
listening for invocation requests.
Any other information needed to uniquely identify the remote object
within its host.

One thing serialized objects do not contain is the actual JVM


instructions (the byte codes), that implement methods on the
local object (e.g. the code for the wrapper methods that
dispatch invoke()).

dbc@csit.fsu.edu

70

Serialization Only Saves the Data

The Java serialization process stores all data fields from the
original object.
It does not store any representation of the code associated
with the methods in the objects class.
When an object is deserialized (e.g. on some client), the client
JVM must have some way of loading a class file that does
contain this information.
If it cannot find a suitable class file, the deserialization
process will fail. You will see a
java.rmi.UnmarshalException thrown, with a nested
java.lang.ClassNotFoundException.
When you are doing development using RMI, you will
probably see this exception a lot!
dbc@csit.fsu.edu

71

Copying Stub Class Files

In RMI, there are at least two ways to get the class files to the
client.
The straightforward approach is to manually copy class files
for all stub classes to the client: either put them in the current
directory on the client, or in some directory on the clients
CLASSPATH.
This approach is reliable, easy to understand, and perhaps the
best approach for initial experiments with RMI.
Eventually you may find it is too limiting. One of the benefits
of the OO approach is supposed to be that the user code (here
the client) doesnt need need to know the exact
implementation class in advanceonly the interface. But
stubs are associated with the implementation class.

dbc@csit.fsu.edu

72

Dynamic Class Loading

A more general approach is to publish implementation class


files that may be needed by clients on a Web Server.
Although the serialized representation of an object does not
contain the actual information from the class file, the
representation can be annotated with a URL. This specifies a
Web Server directory from which the class file can be
downloaded.
When the object is deserialized, the client Java Virtual
Machine transparently downloads the byte codes from the
Web Server specified in the annotation. On the client side,
this process happens automatically.

dbc@csit.fsu.edu

73

Dynamic Class Loading


Serialized stub,
annotated with code-base:
http://myWWW/download/
Remote Object
(MyImpl instance)

Client
JVM

Server

Client

Request stub
class file

Web
Server
html/
download/
MyImpl_Stub.class
dbc@csit.fsu.edu

Server
(myWWW)
74

Remarks

In simple examples, the serialized stub will probably be


obtained through an RMI registry running on the server (the
same server where the remote object is running).
The two serversthe server where the remote object is
running, and the Web Server publishing the class filesmay,
of course, be physically the same machine.

dbc@csit.fsu.edu

75

The java.rmi.server.codebase Property

We need a way to cause serialized object representations to be


annotated with suitably chosen URLs.
In principle this is straightforward. We set a property called
java.rmi.server.codebase in the JVM where the stub (or
serialized object in general) originates.
The value of this property is a code-base URL.
The RMI serialization classes read the code-base property,
and embed the URL they find there in the serialized
representation of arguments or results.
Unless this JVM itself downloaded the class file for the object from a
Web server, in which case they embed the URL from which the class
was originally loaded.

dbc@csit.fsu.edu

76

Properties

java.rmi.server.codebase is one of the JVM default system


properties (see documentation for class System).

Values of properties in general, and


java.rmi.server.codebase in particular, can be set on the java
command-line, or through system calls.

On the command-line, you can set the value of a property with


name prop to value val by using the D option, as in:
java Dprop=val MyClass

Within a running program, you can call the static method


setProperty(), as in:
System.setProperty(prop, val) ;

Here both prop and val must be String-valued expressions.


(There is a related getProperty() method.)
dbc@csit.fsu.edu

77

Setting the Code-base

For example, our original HelloServer example might be run as


follows:
java Djava.rmi.server.codebase=http://sirah.csit.fsu.edu/users/dbc/ HelloServer

This sets the java.rmi.server.codebase property to:


http://sirah.csit.fsu.edu/users/dbc/

This URL gets embedded in serialization streams created by the


HelloServer program.

If an object is subsequently recreated by deserialization in a different


JVM (and that JVM cannot find a local copy of the associated class
file) it will automatically request it from the Web server sirah,
looking in the document directory users/dbc/.

dbc@csit.fsu.edu

78

Recap: Marshalling and the Code-base

When an object is marshaled for an RMI invocation, the


serialized object may be annotated with a URL:
If the class of the object was originally loaded from the local
CLASSPATH, the embedded URL will be the value of the local
java.rmi.server.codebase property.
If the class of the object was originally loaded dynamically from some
Web Server directory, the embedded URL will be the URL for that
directory.

dbc@csit.fsu.edu

79

Recap: Unmarshalling and Loading

When an object is unmarshaled after an RMI invocation, if the


class of the object is not already loaded into the JVM, then:
If the class can be found on the local CLASSPATH, it is loaded from
there.
Otherwise, the class is loaded dynamically from a Web Server
directory specified in the URL embedded in the serialized object.

If the loaded class uses further classes, not already loaded into
the JVM:
If the used class can be found on the local CLASSPATH, it is loaded
from there.
Otherwise, the class is loaded dynamically from the same URL as the
first class.

This rule applies recursively.

dbc@csit.fsu.edu

80

Security Managers

There is one more thing we need to worry about.


Before a Java application is allowed to download code
dynamically, a suitable security manager must be set. This
means a security policy must also be defined.
In general this is a complicated topic. We wont go into any
detail: just give a recipe you can follow.

dbc@csit.fsu.edu

81

Setting the Security Manager

In an RMI application, if no security manager is set, stubs and


classes can only be loaded from the local CLASSPATH.

To enable dynamic loading, issue the command:


System.setSecurityManager(new RMISecurityManager()) ;

at the start of the program.

You should do this in any application that may have to


download codein the simple examples considered so far this
means RMI clients that need to download stubs.

This isnt the end of the story. You also have to define a new
property: the java.security.policy property.
In simple cases this property is needed for clients, whereas
java.rmi.server.codebase is needed for servers.
dbc@csit.fsu.edu

82

Defining a Security Policy

The simplest security policy you can define is a plain text file with
contents:
grant {
permission java.security.AllPermission , ;
};

This policy allows downloaded code to do essentially anything the


current user has privileges to do:
Read, write and delete arbitrary files; open, read and write to arbitrary
Internet sockets; execute arbitrary UNIX/Windows commands on the local
machine, etc.

It is a dangerous policy if there is any chance you may download


code from untrustworthy sources (e.g. the Web).

For now you can use this policy, but please avoid dynamically
loading code you cannot trust!
dbc@csit.fsu.edu

83

The java.security.policy Property

If the text file containing our security policy is called (for


example) policy.all, the original HelloClient example might
now be run as follows:
java Djava.security.policy=policy.all HelloClient

Alternatively this property can be set inside the program using


System.setProperty().

dbc@csit.fsu.edu

84

Using Dynamic Loading

In principle, modifying your RMI application to allow dynamic


loading of stub classes is now straightforward:
Install the stub classes in a Web Server document directory.
Set the java.rmi.server.codebase property for the server application, to
reference that Web Server directory.
Create a security policy file on the client.
Set the java.security.policy property for the client application.
Set a security manager in the client.

This also works for any classes (not just stubs) whose serialized
form may be communicated via remote method calls. You just
need to reinterpret server and client application according to
the direction the serialized object movesas source and
destination application.

In practice. . .
dbc@csit.fsu.edu

85

Anything that Can Go Wrong Will!

Unfortunately, there are many opportunities for trivial


mistakes.

Nearly all mistakes, or combinations of mistakes, seem to


produce the same error reporta
java.rmi.UnmarshalException, with a nested
java.lang.ClassNotFoundException.

This can get pretty frustrating. Suppose


originally you make two mistakes. By trial
and error you may successfully correct one
of them. But you never know whether you
made progress, because correcting one
mistake doesnt change the error message!

dbc@csit.fsu.edu

86

Tips for Dynamic Class Loading

First and foremost: make sure your application works without


dynamic class loading. Try copying the stub files manually,
first.
Be aware of firewalls.

Consider using internal registries (see the following slides).


Consider setting properties inside the Java code (or perhaps
inside scripts that run the java command) and be very careful
about typing errors!
Dont forget the / at the end of the code-base URL.

Make sure your dynamically loadable class files really are


visible on the Web.
Typically the files need to be world readable.

dbc@csit.fsu.edu

87

Problems with the Registry

The registry is one source of problems.


If you use the rmiregistry command in conjunction with
dynamic stub loading, you must be very careful to ensure that
the registry program CAN NOT find the stub class files on its
own CLASSPATH (or in the directory where the
rmiregistry command is run).
If the registry does find the class files on its own
CLASSPATH, it will load them from there, and ignore the
code-base annotation it receives from the original server!
Later when the registry passes stubs on to the client, they are
no longer annotated with the original code-base, and the client
cannot find the class files!

dbc@csit.fsu.edu

88

Empty CLASSPATH for the Registry

So it is usually recommended you ensure the CLASSPATH


environment variable is empty when you run the rmiregistry
command, and make sure the registry is run in a directory that
contains no class files.

However this still leaves some pitfalls.

When the registry dynamically downloads the class file


MessageWriter_Stub.class, it will also look for
MessageWriter.class in the same place, because recreating a
stub instance depends on the remote interface.

So you will have to publish MessageWriter.class on the Web


Server as well, if only for the benefit of the registry.
True clients probably already have this interface definition available on
their local CLASSPATH.
dbc@csit.fsu.edu

89

Using An Internal Registry

An alternative approach is to use an internal registry object,


created inside the server program using the createRegistry()
method, e.g.:
import java.rmi.* ;
import java.rmi.registry.* ;
public class HelloServer {
public static void main(String [] args) throws Exception {
MessageWriter server = new MessageWriterImpl() ;
Registry reg = LocateRegistry.createRegistry(4965) ;
reg.bind(messageservice, server) ;
}
}

Now the registry simply shares the code-base property of the


server, and correctly annotates stubs sent to the client, even
though their class came from the local CLASSPATH.
dbc@csit.fsu.edu

90

Collecting Things Together

Finally we will go through the Hello example again, this


time illustrating changes to support dynamic loading of the
stub class.
There is no change to the remote MessageWriter classes
themselves.
However we will change the client and server applications,
and the deployment procedure.

dbc@csit.fsu.edu

91

The Server Program

The file HelloServer.java contains the declarations:


import java.rmi.* ;
public class HelloServer {
public static void main(String [] args) throws Exception {
final int regPort = Integer.parseInt(args [0]) ;
System.setProperty(java.rmi.server.codebase,
http://sirah.csit.fsu.edu/users/dbc/) ;
MessageWriter server = new MessageWriterImpl() ;
Registry reg = LocateRegistry.createRegistry(regPort) ;
reg.bind(messageservice, server) ;
}
}

dbc@csit.fsu.edu

92

Remarks

The most crucial change is that the server now sets the
java.rmi.server.codebase property.
In this simplified example the Web Server URL is hardwired into the code.
In production quality code, a better strategy may be to first
check (e.g. using getProperty()) whether a property is
defined on the command-line, and, if not, read it from some
properties file.
Here the port number on which the registry listens is taken
from the first command-line argument. A registry is started
internally.

dbc@csit.fsu.edu

93

A Client Program

The file HelloClient.java now contains the declarations:


import java.rmi.* ;
public class HelloClient {
public static void main(String [] args) throws Exception {
System.setProperty(java.security.policy, policy.all) ;
System.setSecurityManager(new RMISecurityManager()) ;
MessageWriter server =
(MessageWriter) Naming.lookup(
rmi://sirah.csit.fsu.edu:4965/messageservice) ;
server.writeMessage(Hello, other world) ;
}
}

dbc@csit.fsu.edu

94

Remarks

A security policy and an RMI security manager is set.


Remarks on server code, concerning hard-wiring of
property values, apply equally here.
This version looks for a registry on port 4965 on sirah (again
hard-wired into the code).

dbc@csit.fsu.edu

95

Deployment

On the server:
rmic MessageWriterImpl
javac HelloServer

Copy the stub class file MessageWriterImpl_Stub.class


from server to an appropriate Web Server directory. In our
example this will be /home/httpd/html/users/dbc/ on sirah.
Make sure the class file is visible: check with a browser!
Copy the interface definition (either MessageWriter.java or
MessageWriter.class will do) from server to client.
On the client:
javac HelloClient

Make sure the file policy.all exists.

dbc@csit.fsu.edu

96

Running FileClient/FileServer

dbc@csit.fsu.edu

97

Running FileClient/FileServer

dbc@csit.fsu.edu

98

Running FileClient/FileServer

dbc@csit.fsu.edu

99

Running FileClient/FileServer

dbc@csit.fsu.edu

100

Remarks

It probably seems a lot of workjust to avoid manually


copying one stub file from the server to the client.
But this facility for dynamically down-loading class files has
more far-reaching implications.
It is applicable not only to stubs, but any object passed
through a remote method call, where the class of the actual
object received is a specialization (subclass or implementation
class) of the type declared in the remote interface.
One can argue this kind of polymorphism is at the heart of
object-oriented programming. In this sense dynamic class
loading is a prerequisite for doing true object-oriented
programming with remote objects.

dbc@csit.fsu.edu

101

Applets

dbc@csit.fsu.edu

102

Applets

An applet is Java GUI program, embedded in a Web page (an


HTML document).
Typical browsers (Internet Explorer, Netscape) incorporate a
Java Virtual Machine.
The class file for the applet is stored in the Web Servers
document directory, alongside normal HTML files and other
downloadable data.
An applet class will be dynamically loaded into the browsers
JVM the first time it encounters an HTML <APPLET> or
<OBJECT> tag requiring that class. Hence the applet is
executed on the client.
These tags can appear in any normal HTML document.

dbc@csit.fsu.edu

103

Applets Today

Java originally became famous as the language that brought


Web pages to life through applets.
Since then, other technologies for making Web pages
interactive have been widely adopted.
For various commercial and technical reasons applets have
decreased in popularity on the Internet. The virtual machines
in Web browsers have not kept step with developments in the
rest of the Java world.
Applets may still have a future in the Intranet context, where
companies can control versions of browser and Java
development software deployed. But on the Internet, where
many incompatible versions abound, the future of traditional
applets is somewhat unclear.
dbc@csit.fsu.edu

104

Applets in this Course

Caveats notwithstanding, an applet is one natural way to


provide a Web front-end to a stand-alone server program,
especially if the server is implemented as an RMI object.
We wish to illustrate the principles of applet deployment, but
avoid getting bogged down in issues about compatibility
across browsers.
Hence we will only discuss Java 2, Swing applets.
These can be displayed in standard browsers, but the browser
must have the Java Plug-in installed.
Installing the plug-in is easy for Windows.
To view the examples in this lecture you will need access to a browser
with the plug-in installed, or the ability to install the plug-in on a
networked PC.
Alternatively, you can use the applet viewer from the JDK.
dbc@csit.fsu.edu

105

Writing Applets is Easy (if . . .)

This assumption makes writing applets very easy, if you


followed the earlier lecture set on the Java GUI!
In a nutshell, you convert a Swing or AWT-based GUI to an
applet GUI by changing the top level JFrame to a JApplet,
perhaps moving code from the body of the main() method to
the init() method of the JApplet.
There is a fly in the ointment: the applet will only successfully
execute in a browser if it respects the security policy imposed
by the browser.

dbc@csit.fsu.edu

106

Applet Security Policies

Usually browsers will not allow an applet to:

read or write a file on the local computer (the client),


find any sensitive information about the local computer,
find any information about the current user!
make an Internet connection to any computer, except the server from
which they were download (applets can only phone home), or
execute any program on the local computer.

An exception will be thrown in the applet if it tries to do any


of these things.
Note that applets specifically are allowed to communicate
back to the host from which they were downloaded (otherwise
they wouldnt be at all useful for our purposes).

dbc@csit.fsu.edu

107

Example: Application to Applet

Driving code for a trivial Swing application that reads entries from
a file and displays them in a list:
import java.util.* ;
import java.io.* ;
import java.awt.event.* ;
import javax.swing.* ;
. . . declaration of classes FilePanel and FileFrame . . .
public class FileDisplayTest {
public static void main(String [] args) {
FileDisplay frame = new FileDisplay() ;
frame.addWindowListener(new TerminationListener()) ;
frame.setVisible(true) ;
}
}
. . . declaration of class TerminationListener . . .
dbc@csit.fsu.edu

108

The FileDisplay class

The associated JFrame class is:


class FileDisplay extends JFrame{
public FileDisplay() {
Vector lines = new Vector() ;
. . . Read all lines from input file to lines . . .
setTitle(File Entries) ;
setSize(450, 300) ;
getContentPanel().add(new FilePanel(lines)) ;
}
}

The suppressed code reads lines from a file using a


FileReader stream and saves them in the Vector called lines.

dbc@csit.fsu.edu

109

The FilePanel class

The definition of FilePanel is just:


class FilePanel extends JPanel {
public FilePanel(Vector lines) {
JList list = new JList(lines) ;
JScrollPane scrollPane = new JScrollPane(list) ;
add(scrollPane) ;
}
}

dbc@csit.fsu.edu

110

Conversion to an Applet

In this example there is no code in the main() method that


will be needed by the Applet. We simply dispense with
FileFrameTest class (and TerminationListener).
The FileDisplay class is changed to extend JApplet instead
of JFrame.
This class is made public, and we change the source file name
to FileDisplay.java.

dbc@csit.fsu.edu

111

A First Attempt at an Applet Class

Now the FileDisplay class in FileDisplay.java is:


public class FileDisplay extends JApplet {
public FileDisplay() {
Vector lines = new Vector() ;
. . . Read all lines from input file to lines . . .
getContentPanel().add(new FilePanel(lines)) ;
}
}

Note we have violated a security restriction, by attempting to


read a file. We will return to this issue later.

dbc@csit.fsu.edu

112

Compiling the Applet

Copy the Java source to a suitable Web directory.


I will work in the directory:
/home/http/html/users/dbc/examples/

on the host:
sirah.csit.fsu.edu

Compile the applet source file in the usual way:


javac FileDisplay.java

Remember to make the class files world readable:


chmod o+r *.class

Forgetting to do this will lead to many problems!


To be sure, check the permissions using ls l.
Look at the directory using a Web browser (go to URL
http:sirah.csit.fsu.edu/users/dbc/examples/). Can you see the class files?
Will the browser let you save the class files?
dbc@csit.fsu.edu

113

Create an HTML File

This will be the document people point their browser at. It


can be an arbitrarily complicated HTML document, with
surrounding text and images. For now, we use:
<HTML>
<TITLE>A File Display</TITLE>
<BODY>
<APPLET CODE=FileDisplay.class
WIDTH=300 HEIGHT=450></APPLET>
</BODY>
</HTML>

Note the WIDTH and HEIGHT parameters here replace the


setsize() call in a Swing application.
We will assume this text is stored in the file:
filedisplay.html

in the same directory as the applet class files.


dbc@csit.fsu.edu

114

Convert the HTML for the Plug-in

A Java 2 applet that is to displayed through the Java Plug-in


actually needs a more complicated HTML tag. Sun provide a
converter to add the extra HTML.
The converter is a Java program. On sirah you can use the
script htmlconv installed in /usr/local/jdk1.2.2/bin/. It is a
one-line scriptif you prefer, check the definition of the
script file, and invoke the java program directly.
Otherwise, if you are happy to use the script, do:
htmlconv filedisplay.html backup BAK
This saves the original files in a subdirectory BAK/, then overwrites
them.
If you dont specify the -backup option, the original files get saved in
a subdirectory of ./... This is a poor defaultif you dont have
write-permission in this parent directory, the command will fail.
dbc@csit.fsu.edu

115

Make Sure the HTML is Visible!

Make sure the file displayfile.html is world readable:


chmod o+r displayfile.html

Make sure the directory itself is visible:


chmod o+r .

dbc@csit.fsu.edu

116

Installing the Java Plug-in

To view this applet, you will need a browser with the Java
plug-in installed.
If you have a suitable PC where you can install this software,
go to:
http://javasoft.com/products/plugin/

and follow the link for JRE 1.3 for Microsoft Windows.
Download the executable file into a suitable directory on your
PC, and run it.
The plug-in is now installed.
If you are unable to install the plug-in, but have a suitable Java 2 JDK
installation, you can view the applet using the appletviewer command
instead. Pass the URL on the command line.

dbc@csit.fsu.edu

117

Attempting to View the Applet

Now go to the URL:


http://sirah.csit.fsu.edu/users/dbc/examples/filedisplay.html

If things go properly, you should see a blank panel with a


message like:
Applet Loading. . .

On the browser status line you should see a message like:


exception: access denied (java.io FilePermission infile read).

Here infile is the name of the file the applet attempts to


read. Trying to read it is a security violation.
The Applet failed. Exit the browser.
If an applet you are debugging fails, it is nearly always a good idea to
exit the browser before trying to view the applet again.

dbc@csit.fsu.edu

118

Adding a File Reading Service

What we really want is for the Applet to read file entries from
a file on the server.
In fact this limited objective could be achieved with an HTTP
GET request, but a more general approach is to use RMI.

dbc@csit.fsu.edu

119

An Updated File Server Program

A new definition for the class FileServer (see the Mechanics of


RMI section), supporting dynamic class loading:
import java.rmi.* ;
import java.rmi.registry.* ;
public class FileServer {
public static void main(String [] args) throws Exception {
final int regPort = Integer.parseInt(args [0]) ;
System.setProperty(java.rmi.server.codebase,
http://sirah.csit.fsu.edu/users/dbc/examples/) ;
FileSource server = new FileSourceImpl() ;
Registry reg = LocateRegistry.createRegistry(regPort) ;
reg.bind(fileservice, server) ;
}
}
dbc@csit.fsu.edu

120

An Updated Client

Change FileDisplay to read lines from a file called infile on the


server:
public class FileDisplay extends JApplet {
public FileDisplay() {
Vector lines = new Vector() ;
try {
FileSource server = (FileSource)
Naming.lookup(rmi://sirah.csit.fsu.edu:4965/fileservice) ;
lines = server.readFile(infile) ;
// Remote method
getContentPane().add(new FilePanel(lines)) ;
} catch (Exception e) {
}
}
}
dbc@csit.fsu.edu

121

Deploying the Service

Copy the source files FileServer.java, FileSource.java and


FileSourceImpl.java to the Web Server directory where the
applet lives.
Compile the remote object and the server:
rmic FileSourceImpl
javac FileServer.java

Remember to make the class files world readable!:


chmod o+r *.class

Make sure there is a file called infile in this directory!


Run the server:
java FileServer 4965

View the applet with the browser while the server program is
running.
dbc@csit.fsu.edu

122

Class Loading in the Example

The applet class itself, FileDisplay, will be loaded dynamically


by the applet class loader in the browser.
Classes it uses directly, like FilePanel, and the FileSource
remote interface definition, will also be loaded by the applet
class loader.
By default, these class files will be downloaded from the same
directory as the original HTML.
When Naming.lookup() returns a FileSourceImp_Stub object,
this will be loaded by the RMI class loader in the browser JVM.
As usual, the class file will be downloaded from a directory
determined by the java.rmi.server.codebase property in the
server program.
In the example, both loaders read from the same directory.
dbc@csit.fsu.edu

123

Running Server Programs in UNIX

In this example, we assumed the server program is running in


a window of its own.
In UNIX, you can run a process in the background by adding
an ampersand to the command:
java FileServer 4965 &

This process can go on running even after you log out.


If you use this mechanism, make sure you know how to kill
the process when it is no longer needed, e.g.:
sirah$
PID
30399
30355
...
sirah$

ps udbc
TTY
TIME CMD
?
00:00:00 java
pts/2
00:00:00 bash

# Processes of user dbc

kill -9 30399

# The process ID
dbc@csit.fsu.edu

124

What Did this Achieve?

The exampledisplaying a file from the serverwas


contrived to be very simple.
But it should be clear that now we have a general mechanism
whereby an applet running in a browser can communicate
with a program running on the server.
Through remote methods, the applet client can effectively
cause arbitrary code to be executed on the server.
This opens many options that are not available to an applet by
itself:
The server program can do many things an applet itself cannot do, due
to security restrictions.
Instances of the applet, running in browsers belonging to different
clients, can share access to data or databases that reside on the server.

dbc@csit.fsu.edu

125

Some Additional Features of Applets

Applets are not a primary focus of these lectures, but we briefly review
some of their other properties.
In the FileDisplay example, the GUI was created in the constructor of the
applet.
This is slightly unusual for an applet. It is more traditional to do
initialization in a method called init()one of several applet eventhandling methods:
init()
start()
stop()
destroy()

Actually these methods are not invoked in the AWT event-dispatching


thread. You should take appropriate care, especially if start() or stop()
explicitly modifies the displaysee the section Events Revisited in the
GUI lectures.
dbc@csit.fsu.edu

126

Life Cycle of an Applet

The system invokes four methods on JApplet:


void init()
when the applet is first loaded.
void start()
after init() and whenever the browser reloads the HTML page
containing the applet.
void stop()
whenever the browser leaves the HTML page containing the applet.
void destroy()
before the browser shuts down.

Note that an applet is apparently never unloaded once it has


been loaded (until the browser exits). This can be awkward
for debugging (and presumably means the browser JVM
eventually fills up with classes).
dbc@csit.fsu.edu

127

Applet Parameters

The APPLET element in HTML can include parameter


definitions, e.g.:
<APPLET CODE=FileDisplay.class
WIDTH=300 HEIGHT=450>
<PARAM NAME=file VALUE = infile>
<PARAM NAME=port VALUE = 4965>
</APPLET>

Inside the applet, these parameters are read by


getParameter(), e.g.:
String file = getParameter(file) ;

You are not allowed to call this method in the applet


constructor. This is one reason for doing initialization in
init().
Remember to convert the HTML again if you modify the
applet element!
dbc@csit.fsu.edu

128

An Improved Applet

This version will read the port number (and file name) from
the applet parameters:
public class FileDisplay extends JApplet {
FileSource server ;
FilePanel panel = new FilePanel() ;
public void init() {
try {
getContentPane().add(panel) ;
server = (FileSource)
Naming.lookup(rmi://sirah.csit.fsu.edu: +
getParameter(port) +
/fileservice) ;
} catch(Exception e) { . . . }
}
...
}
dbc@csit.fsu.edu

129

An Improved Applet

. . . it also reads the file again whenever the page is refreshed:


public class FileDisplay extends JApplet {
...
public void start() {
try {
panel.setLines(server.readFile(getParameter(file))) ;
} catch(Exception e) { . . . }
}
}

We added a default constructor and setLines() method to


FilePanel(). Latter uses setListData() method of JList.

dbc@csit.fsu.edu

130

stop()

If you are writing a more general applet that allows the file to
be updated, overriding the stop() method might be one natural
place to save locally cached data back to the server.

dbc@csit.fsu.edu

131

Other Applications of RMI

dbc@csit.fsu.edu

132

Beyond Simple Client/Server

The preceding example illustrated how to use RMI to


implement a back-end server program for a client, which
might be an applet running in a Web browser.
RMI can do this easily, but it also allows one to do much
more general things.

dbc@csit.fsu.edu

133

Example: Exploiting Dynamic Loading

We emphasized in an earlier section that the dynamic class


loading implemented in RMI goes beyond automated delivery
of stub classes.
Objects of essentially any class can be returned by a remote
method, and the code will be dynamically downloaded. For
example, this may include code for complex graphical user
interfaces.

dbc@csit.fsu.edu

134

A Generic Service

One could define a generic service remote interface:


public interface GenericService extends Remote {
public GUI getGUI() ;
}
public interface GUI extends Serializable {
public void init() ;
}

The client simply does:


GenericService service = (GenericService) Naming.lookup(url) ;
GUI gui = service.getGUI() ;
gui.init() ;
// Start GUI running locally

All the client knows in advance are the two simple interfaces
GenericService and GUI. The code for the actual service
and GUI are downloaded dynamically. The GUI might be an
arbitrary Swing interface.
dbc@csit.fsu.edu

135

Example: Jini

Suns Jini is a framework for spontaneous discovery of


services that exist in a LAN (for example), and for reliable
federation of these services.
It makes essential (and creative) use of aspects of RMI like
dynamic class loading and call-backs (discussed next).
The Jini lookup services generalize the RMI registry. In Jini
an arbitrary proxy object is installed in the lookup services.
The proxy is not restricted to be an RMI stub. It can be any
serializable object, typically including remote references to an actual
server object.

The code for the proxy is downloaded dynamically by the


client, on lookup.

dbc@csit.fsu.edu

136

Example: Call-backs

A client can itself provide a remote interface, by creating its


own remote object.
It can then pass a reference to itself to a server. Now the
server can initiate communication by calling remote methods
on the client. These are sometimes called call-backs.
In following pages, we outline a collaboration server example.
We omit many details.
In general we see that RMI allows one to create complex
webs of interacting objects.

dbc@csit.fsu.edu

137

Server Remote Interface

A collaboration server allows users to register it, and to post


messages.
It keeps a list of users. When any user posts a message, it
distributes it to all the other users.
public interface ChatServer extends Remote {
public void register(Chatter c, String name)
throws RemoteException ;
// c is a remote reference to client object.
public void postMessage(Message m)
throws RemoteException ;
...
}

The Message class must implement Serializable.


dbc@csit.fsu.edu

138

Client Remote Interface

The client itself is implemented as a remote object with


interface:
public interface Chatter extends Remote {
public void notify (Message m) throws RemoteException ;
...
}

The notify() method will be called by the server when a


message has been posted.

dbc@csit.fsu.edu

139

A Group of Interacting Objects


postMessage(m)
Remote Object
(ChatServer_Impl)

Remote Object
(Chatter_Impl)

notify(m)

Server
notify(m)
notify(m)

Client
Remote Object
(Chatter_Impl)

Client
dbc@csit.fsu.edu

Remote Object
(Chatter_Impl)

Client
140

Sketch of Server Implementation


public class ChatServerImpl extends UnicastRemoteObject
implements ChatServer {
private Vector chatters = new Vector();
public ChatServerImpl() throws RemoteException {}
public void register(Chatter c, String name) {
chatters.addElement (c);
}
public void postMessage (Message m) {
for(int i = 0 ; i < chatters.size() ; i++) {
Chatter chatter = (Chatter) chatters.get(i) ;
chatter.notify(Message m) ;
}
}
public static void main(String[ ] args)
. . . set security manager, bind to registry, etc . . .
}
}
dbc@csit.fsu.edu

141

Sketch of Client Implementation


public class ChatterImpl extends UnicastRemoteObject
implements Chatter {
public ChatterImpl(ChatApplet gui, String name)
throws RemoteException() {
this.gui = gui ;
server = (ChatServer)Naming.lookup(. . .);
server.register(this, name) ;
// Register self with chat server
}
public void notify(Message m) throws RemoteException
gui.displayMessage(m) ;
}
...
}

We assume this implementation object is created by an applet,


which passes itself to the remote object constructor. It should
implement displayMessage().
dbc@csit.fsu.edu

142

Synchronization

Where multiple clients may interact with the same object (this
means most useful services), one needs to pay attention to
issues of interference.
Remote invocations from different clients may execute
concurrentlyin different threadsin the server programs
JVM.
It can be a good idea to declare the implementation of remote
methods (in the definition of the implementation class) with
the synchronized modifier.
This avoids the dangerous situation in which methods are
being invoked simultaneously on a remote object by several
clients.
Other clients will have to wait until the currently executing method has
completedthey will be serviced in turn.
But now you must be wary of possible deadlocks.
dbc@csit.fsu.edu

143

Enterprise Java Beans

Enterprise Java Beans (EJB) is a specification for a server


software framework, emphasizing transactions in distributed
environments.
It uses the RMI as the basic communication model, but has
higher leveland more specializedsupport for
automatically handling issues of concurrency and transaction
processing, and automatically managing persistence (saving
state of objects to databases).

dbc@csit.fsu.edu

144

Garbage Collection

For Java, an important issue is garbage collection, which


automatically deallocates memory for local objects.
Remote objects are also garbage collected as follows:
A remote reference layer on the server keeps a reference count for each
locally held remote object implementation.
A remote reference layer on the client notifies the server when its locally
held references to the object are no longer in use.
When all references from all clients have gone (i.e. when the reference
count is zero), the server object is garbage collected.

But what if a client fails to notify the server?


A client with a remote reference must periodically renew a lease with the
run-time system on the server.
If the client holding the reference exits prematurely (without notifying the
server) it will also stop renewing its leases. If a lease is not renewed on
time, the server assumes the client has died, and the reference count is
decremented anyway.
dbc@csit.fsu.edu

145

You might also like