You are on page 1of 25

HET715 Network Computing

Lecture 7
Remote Method Invocation (RMI)

Objectives
To introduce Remote Procedure Call (RPC) technologies To introduce Remote method invocation (RMI) To describe the basic RMI process To implement RMI using Java To compile and execute the RMI application

Remote Procedure Calls (RPC)


All our methods so far have been invoked on local objects In a real-life distributed environment it is often desirable to invoke methods on objects located on other (remote) systems RPC Technologies allow a client to find and then invoke (call) methods on a remote object (server) in such a way that it looks like the server is a local object

RPC Technologies

Several RPC technologies are available which operate in a similar fashion:


Remote Method Invocation (RMI) is the main Java oriented technology (covered in this lecture) Common Object Request Broker Architecture (CORBA) is an older technology found in industry but rarely used in new projects (covered in another lecture) Web Services is a more recent technology based on Extensible Markup Language (XML) (covered in another lecture) Distributed Component Object Model (DCOM) is an even older, less common Windows-based technology (not covered in this unit)

What is RMI?
RMI is a platform-independent RPC technology which has been a core component of the Java language from its inception Under RMI networking details required by explicit programming of streams and sockets disappear RMI infrastructure handles the use of byte streams to transfer data and method invocations behind the scenes Once a reference to the remote object is obtained the methods of that object can be invoked as if the object was local The fact that an object is located remotely is almost transparent to a Java programmer

Remote Method Invocation

Object Client

network method invocation

Remote Object Server

Host: swin.edu.au

Host: csu.edu.au

Remote Method Invocation

Local Machine (Client)


SampleServer remoteObject; int s; s = remoteObject.sum(1,2);

Remote Machine (Server)

1,2
public int sum(int a,int b) { return a + b; }

3
System.out.println(s);

The basic RMI process


The server program that has control on the remote object registers an interface with a naming service The interface contains the signatures of those methods of the object that the server wishes to make publicly available A client program then uses the same naming service to obtain a reference to this interface in the form of what is called a stub which acts as a local proxy for the remote object On the remote server there will be another proxy called a skeleton When the client program invokes a method of the remote object, it appears (to the client) that the method is being invoked directly on the object

Naming Service (rmiregistry)


Directory that associates names to remote objects (bind/rebind)
Remote Object A

Naming X Y

Remote Object B Host: csu.edu.au

Remote Object C

Naming Service (cont.)


Client uses Naming Service to find a particular remote object (lookup)

Naming
Object Client lookup(Y) X Y Remote Object

Reference to Remote object


swin.edu.au

Host: csu.edu.au

What actually happens


An equivalent method is being called in the stub (proxy on the local machine) The stub then forwards the call and any parameters (via marshalling) to the skeleton (proxy on the remote machine) Upon receipt of the byte stream the skeleton converts this stream into the original method call and associated parameters (via unmarshalling) The skeleton then calls the implementation of the method on the server If the method has a return value then the above process is reversed with the return value being serialized on the server (by the skeleton) and deserialized on the client (by the stub)

The basic RMI process

Sending parameters and return values


Recall that we can pass zero or more parameters to a method which returns one or no value (void) to the calling code. These can be simple values like a number (int) or text (String) (these types are readily serializable objects), or a complex object (eg. Customer) When sent over a network, such values need to be encoded into a stream of bytes that can be transmitted on a stream through the socket. This is called Marshalling

When received, the stream of bytes need to be decoded back into object. This is called Unmarshalling

Serialization
Marshalling & Unmarshalling parameters and return values is usually achieved by using a process called Serialization, a facility automatically available in Java and similar modern software technologies Normally objects pass a copy of their data contents to/from the server by serialization

Serialization allows one to convert object data into raw bytes and reconstruct the object data from bytes
Objects of a given class sent/received via serialization only have to implement the serialization interface

This is done by importing java.io.Serializable and then stating in the class definition that the class implements the Serializable interface

The packages and steps of implementation

Three packages are used for an RMI client/server application (only first two need to be used explicitly):
java.rmi java.rmi.server java.rmi.registry

Four steps are involved as follows:


Create the interface to be registered Define a class that implements this interface Create the server process Create the client process

An example for RMI


The example application that follows is simply used to illustrate the fundamental principles of RMI It just displays a greeting to any client that uses the appropriate interface registered with the naming service to invoke the associated method implementation on the server In a more realistic application there would (probably) be more methods and (possibly) more objects involved

Step-1: Create the interface


This interface must import package java.rmi and extend interface Remote which contains no methods

The interface definition for this example must specify the signature for method getGreeting which is to be made available to clients
This method must declare that it throws a Remote Exception
//RMI interface. import java.rmi.*;

//(1)

public interface Hello extends Remote //(2) { public String getGreeting() throws RemoteException; //(3) }

Step-2: Define a class that implements the interface


The implementation class (HelloImpl) should import packages java.rmi and java.rmi.server and extend RemoteObject class or one of its subclasses In practice most implementations extend the UnicastRemoteObject subclass since it supports point-to-point communication using TCP A constructor must be provided (even if it has an empty body as in the example) for the implementation object which (like the methods declared in the interface) must declare that it throws a Remote Exception The implementation class must also implement the interface created previously (ie. the Hello interface) by providing an executable body for the single interface method (getGreeting)

The implementation of the interface


//Implementation of RMI interface. import java.rmi.*; import java.rmi.server.*; //(1) //(1)

public class HelloImpl extends UnicastRemoteObject implements Hello //(2) { { (imp class) public HelloImpl() throws RemoteException (imp interface) //(3)

//No action needed here (but must provide a constructor).


} public String getGreeting() throws RemoteException { return ("Hello there!"); } } //(4)

Step-3: Create the server process


The server creates an object of the implementation class (HelloImpl) and registers it with a naming service called rmiregistry It does this by using the static method rebind of class Naming from package java.rmi (ie. public static void Naming.rebind(String name, Remote object ) This method takes two arguments:
A String that holds the name of the remote object as a URL with protocol rmi A reference to the remote object

It establishes an association between the objects name (the URL) and its reference after which clients are able to retrieve a reference to that object via the registry The URL string as well as specifying a protocol of rmi and a name for the object, specifies the name of the remote objects host machine The default for RMI host is localhost (which is used in our example for simplicity) and the default port for RMI is 1099 (can use others of course) The example has only one method (main) and to cater for various types of exceptions that may be generated it throws Exception

Creating the server process


//Server. import java.rmi.*; public class HelloServer //(1)

{
private static final String HOST = "localhost"; public static void main(String[] args) throws Exception { //(2)

HelloImpl temp = new HelloImpl();

//(3)

String rmiObjectName = "rmi://" + HOST + "/Hello"; //naming URL //Could omit host name in this example, //since 'localhost' would be assumed by default. Naming.rebind(rmiObjectName, temp); System.out.println("Binding complete...\n"); } } //(4)

Step-4: Create the client process


The client obtains a reference to the remote object from the registry by using the static method lookup of the Naming class from package java.rmi (ie. public static Remote Naming.lookup(String name) It supplies the URL to the method as the argument (same URL as the one that the server used when binding the object reference to the object name in the registry) Since lookup returns a Remote reference this reference must be type cast into a Hello reference (note: not a HelloImpl reference) Once the Hello reference has been obtained it can be used to call the solitary method that was made available in the interface

Creating the client process


//Client. import java.rmi.*; public class HelloClient{ private static final String HOST = "localhost"; public static void main(String[] args) throws Exception //(1)

{
try { Hello greeting = (Hello)Naming.lookup("rmi://" + HOST + "/Hello"); // Hello type casting. //Simply retrieve and display greeting... System.out.println("Message received: + greeting.getGreeting()); } catch(ConnectException conEx) { System.out.println("Unable to connect to server!"); System.exit(1); } //(3) //(2)

catch(Exception ex)
{ ex.printStackTrace(); System.exit(1); } } }

Compilation and execution


1. Compile all files with javac
javac Hello.java javac HelloImpl.java javac HelloServer.java javac HelloClient.java OR javac *.java

2.

Compile the implementation class with the rmic compiler to create the stub and perhaps skeleton (older versions of Java) classes
rmic HelloImpl

3. 4. 5.

Start the RMI registry


rmiregistry

Open a new window and run the server


java HelloServer

Open a third window and run the client


java HelloClient

If you are running client and server on different machines (this is usually the case in real life applications)
1. 2. Compile all files as in previous slide (step 1 and 2 in the preceding slide) Make sure rmiregistry and the server related files are in the same folder, running in the same order (ie. rmiregistry first) but in different DOS command windows on the same machine The server side folder should have the following files:
HelloServer.class Hello.class HelloImpl.class HelloImpl_Stub.class

3.

4.

The client side folder should have the following files:


HelloClient.class Hello.class HelloImpl_Stub.class

You might also like