Professional Documents
Culture Documents
17 November 2011
1 Introduction
In this document we will start with a brief set of reminders about RMI (Section 2). Then we will provide a
working toy example (Section 3). So, you can get acquainted with programming, compiling, and running
RMI programs. Finally, we explain what you have to do for Exercise 3 (Section 4). We advice the
students to follow this document. However, if you are confident about your programming skills, then you
can skip sections 1 and 2.
2 Reminders on RMI
Java Remote Method Invocation (RMI) enables the programmer to write distributed Java programs. In
particular, RMI makes it possible for Java programs to invoke methods of (remote) objects that possibly
reside on a different (remote) computer.
The architecture that makes RMI possible consists of three parties: (i) a client, (ii) a server, and (iii)
a naming service (rmiregistry). The client is the process that invokes a method on a remote object.
In contrast, the server is the process that owns the remote object. This remote object is just another
ordinary object in the address space of the server. Finally, the rmiregistry is a name server that has
a table that maps objects to remote references. To clarify, servers that want to provide RMI services
register their remote objects at the rmiregistry. In addition, clients that look for a specific remote
object can contact the rmiregistry to get a remote reference for the required remote object.
We also have to remind you about several things related to the rmiregistry.
• Each machine that hosts remote Objects needs to have a rmiregistry name server running.
– rmiregistry <port>
– If you do not specify a port number, then it will make use of port 1099 by default.
Finally, you should also remember that in RMI, by default the parameters are passed by value. If you
do not take this into account you can cause huge data transfers. To clarify this, consider the following.
Let us assume we give a remotely invoked method, the head of a LinkedList that contains database entries
as a parameter. In this case, the whole list and all the data that each node in the list refers to are passed
to the server.
1
Now we know what we have to write, we can continue with our example. In this example we will
write a calculator RMI client/server program. The first thing that we want to write is the interface
of the calculator. In our case the calculator can only perform additions and subtractions. So, the
Calculator.java interface is specified as follows:
1 public i n t e r f a c e C a l c u l a t o r extends j a v a . rmi . Remote {
2 public long add ( long a , long b )
3 throws j a v a . rmi . RemoteException ;
4
5 public long sub ( long a , long b )
6 throws j a v a . rmi . RemoteException ;
7 }
Now that we have the interface we can write the implementation of the remote object as follows.
1 public c l a s s C a l c u l a t o r I m p l extends
2 j a v a . rmi . s e r v e r . UnicastRemoteObject
3 implements C a l c u l a t o r {
4
5 // I m p l e m e n t a t i o n s must have
6 // an e x p l i c i t c o n s t r u c t o r
7 public C a l c u l a t o r I m p l ( )
8 throws j a v a . rmi . RemoteException {
9 super ( ) ;
10 }
11
12 public long add ( long a , long b )
13 throws j a v a . rmi . RemoteException {
14 return a + b ;
15 }
16
17 public long sub ( long a , long b )
18 throws j a v a . rmi . RemoteException {
19 return a − b ;
20 }
21 }
The implementation of the remote objects also have to adhere to some rules:
• It must implement the interface for the remote object
• It must inherit from the java.rmi.server.UnicastRemoteObject class
• It must have an explicit constructor which throws the java.rmi.RemoteException exception
We can compile the code for the implementation of the remote object by giving the following command
at a Linux shell:
1 $ javac CalculatorImpl . java
The next item on the list of files that we have to implement is the server that will run the remote
object. In our toy example this remote server is implemented as follows:
1 import j a v a . rmi . Naming ;
2
3 public c l a s s C a l c u l a t o r S e r v e r {
4
5 public C a l c u l a t o r S e r v e r ( ) {
6 try {
7 // The s e r v e r c r e a t e s an C a l c u l a t o r I m p l o b j e c t
2
8 Calculator c =
9 new C a l c u l a t o r I m p l ( ) ;
10
11 // I t b i n d s ( r e g i s t e r s ) t o t h e r m i r e g i s t r y
12 // s y n t a x name parameter o f r e b i n d
13 // rmi :// < host name > [ : p o r t ]/< s e r v i c e n a m e >
14 Naming . r e b i n d ( ” rmi : / / l o c a l h o s t / C a l c u l a t o r S e r v i c e ” , c ) ;
15 } catch ( E x c e p t i o n e ) {
16 System . out . p r i n t l n ( ” Trouble : ” + e ) ;
17 }
18 }
19
20 public s t a t i c void main ( S t r i n g a r g s [ ] ) {
21 new C a l c u l a t o r S e r v e r ( ) ;
22 }
23 }
You can compile the server as follow by giving the following command at a Linux shell:
1 $ javac CalculatorServer . java
The last class that we have to implement to complete our toy example is the client. The client is
implemented as follows:
1 import j a v a . n e t . MalformedURLException ;
2 import j a v a . rmi . Naming ;
3
4 public c l a s s C a l c u l a t o r C l i e n t {
5 public s t a t i c void main ( S t r i n g [ ] a r g s ) {
6 try {
7 // B e f o r e c o n t a c t i n g t h e s e r v e r you have
8 // t o l o o k him up f i r s t
9 Calculator c = ( Calculator )
10 Naming . l ook up ( ” rmi : / / l o c a l h o s t / C a l c u l a t o r S e r v i c e ” ) ;
11
12 // We now have t h e same i n t e r f a c e as t h e s e r v e r
13 // So we can j u s t i n v o k e t h e methods l i k e t h e y were l o c a l
14 System . out . p r i n t l n ( c . add ( 4 , 5 ) ) ;
15 System . out . p r i n t l n ( c . sub ( 4 , 3 ) ) ;
16 } catch ( E x c e p t i o n e ) {
17 System . out . p r i n t l n ( ” R e c e i v e d E x c e p t i o n : ” ) ;
18 System . out . p r i n t l n ( e ) ;
19 }
20 }
21 }
So, we are finished with the toy example. If you followed the instructions step by step, then everything
should be correct and working. To start testing this toy example you should do the following:
• Make sure that the rmiregsitry has access to all class files of the server
If you want to test this client server program in a distributed way then you have to ensure the following
point:
– Calculator.class
– CalculatorImpl.class
3
– CalculatorServer.class
• You should also change the address of the server that your trying to send remote method invocations
to.
• We have 3 rooms of type 3 which are triple rooms that costs 150 Euros a night
• We have 2 rooms of type 4 which are quad rooms that costs 230 Euros a night
To implement this system you will have to write a server HotelServer, a client HotelClient, a
remote interface RoomManager, and the implementation of the remote interface RoomManagerImpl.
The hotel client HotelClient can be run from a Linux shell by entering the following commands:
• java HotelClient: If no options are supplied HotelClient just prints and shows how this com-
mand can be used.
• java HotelClient list <server address>: list the available number of rooms in each price
range. The output should look like the following:
– The values of v, w, x, y, and z should be the current number of available rooms for each
type of room.
• java HotelClient book <server address> <room type> <guest name>: books a room of
the specified type (if available), and registers the name of the guest.
• java HotelClient guests <server address>: list the names of all the registered guests
So, for the list, book, and guests options the HotelClient remotely invokes associated methods in
a remote object. The HotelClient gets the results of these remote method invocations back from the
HotelServer, and prints them out on its standard output.