remote method invocation

20
SRI KRISHNA ARTS AND SCIENCE COLLEGE Java assignment Topic: Remote Method Invocation (RMI) By, ARUN.P

Upload: arun-nair

Post on 02-Aug-2015

9 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: remote method invocation

SRI KRISHNA ARTS AND SCIENCE COLLEGE

Java assignmentTopic:

Remote Method Invocation (RMI)

By,

ARUN.P13BCA005

INTRODUCTION

Page 2: remote method invocation

The Remote Method Invocation (RMI) facilitates object function calls between Java Virtual Machines (JVMs). JVMs can be located on separate computers - yet one JVM can invoke methods belonging to an object stored in another JVM. Methods can even pass objects that a foreign virtual machine has never encountered before, allowing dynamic loading of new classes as required. This is a powerful feature!

Consider the follow scenario:

Developer A writes a service that performs some useful function. He regularly updates this service, adding new features and improving existing ones.

Developer B wishes to use the service provided by Developer A. However, it's inconvenient for A to supply B with an update every time.

Java RMI provides a very easy solution! Since RMI can dynamically load new classes, Developer B can let RMI handle updates automatically for him. Developer A places the new classes in a web directory, where RMI can fetch the new updates as they are required.

Figure 1 - Connections made when client uses RMI

Figure 1 shows the connections made by the client when using RMI. Firstly, the client must contact an RMI registry, and request the name of the service. Developer B won't know the

Page 3: remote method invocation

exact location of the RMI service, but he knows enough to contact Developer A's registry. This will point him in the direction of the service he wants to call..

Developer A's service changes regularly, so Developer B doesn't have a copy of the class. Not to worry, because the client automatically fetches the new subclass from a webserver where the two developers share classes. The new class is loaded into memory, and the client is ready to use the new class. This happens transparently for Developer B - no extra code need to be written to fetch the class.

HOW RMI WORKS?

When referencing a remote object residing on machine B from code being on machine a there are always two intermediate objects actually handling the communication: a stub object and a skeleton object. When a remote method invocation comes up the following tasks are handled by these two objects (see also figure):

The stub object (on machine A) has to

o build an information block thats consists of an identifier of the remote object to be used, an operation number describing the method to

be called and the marshalled parameters (method parameters

have to be encoded into a format suitable for transporting them across the net)

o send this information to the server

The tasks of the skeleton object (on machine B) are

o to unmarshal the parameters,

Page 4: remote method invocation

o to call the desired method on the real object lying on the server,

o to capture the return value or exception of the call on the server,

o to marshal this value,o to send a package consisting of the value in the

marshalled form back to the stub on the client, machine A.

The stub object unmarshals the return value or exception from the server. This value becomes the return value of the remote method invocation. Or, if the remote method threw an exception, the stub (object) rethrows it in the process space of the caller.

Example

Let's assume there is a remote object belonging to the class Product offering the method getDescription(), whose return value is a String object. Let's further assume this method is invoked by a remote machine (not very surprising). The following figure shows what is going on in order to handle this

Page 5: remote method invocation

situation, on client side as well as on server side.

UNDERSTANDING STUB AND SKELETON

Page 6: remote method invocation

RMI uses stub and skeleton object for communication with the remote object.

A remote object is an object whose method can be invoked from another JVM. Let's understand the stub and skeleton objects:

Stub

The stub is an object, acts as a gateway for the client side. All the outgoing requests are routed through it. It resides at the client side and represents the remote object. When the caller invokes method on the stub object, it does the following tasks:

1. It initiates a connection with remote Virtual Machine (JVM),2. It writes and transmits (marshals) the parameters to the

remote Virtual Machine (JVM),3. It waits for the result4. It reads (unmarshals) the return value or exception, and5. It finally, returns the value to the caller.

Skeleton

The skeleton is an object, acts as a gateway for the server side object. All the incoming requests are routed through it. When the skeleton receives the incoming request, it does the following tasks:

1. It reads the parameter for the remote method2. It invokes the method on the actual remote object, and3. It writes and transmits (marshals) the result to the caller.

Page 7: remote method invocation

Steps to write the RMI program

This is given the 6 steps to write the RMI program.

1. Create the remote interface2. Provide the implementation of the remote interface3. Compile the implementation class and create the stub and

skeleton objects using the rmic tool4. Start the registry service by rmi registry tool5. Create and start the remote application6. Create and start the client application

Writing RMI services

Writing your own RMI services can be a little difficult at first, so we'll start off with an example which isn't too ambitious. We'll create a service that can calculate the square of a number, and the power of two numbers (238 for example). Due to the large size of the numbers, we'll use the java.math.BigInteger class for returning values rather than an integer or along.

Writing an interface

Page 8: remote method invocation

The first thing we need to do is to agree upon an interface, An interface is a description of the methods we will allow remote clients to invoke. Let's consider exactly what we'll need.

1. A method that accepts as a parameter an integer, squares it, and returns a BigIntegerpublic BigInteger square ( int number_to_square );

2. A method that accepts as a parameter two integers, calculates their power, and returns a BigIntegerpublic BigInteger power ( int num1, int num2 );

Once we've decided on the methods that will compose our service, we have to create a Java interface. An interface is a method which contains abstract methods; these methods must be implemented by another class. Here's the source code for our service that calculates powers.

import java.math.BigInteger;import java.rmi.*;

//// PowerService Interface//// Interface for a RMI service that calculates powers//public interface PowerService extends java.rmi.Remote{

// Calculate the square of a numberpublic BigInteger square ( int number )

throws RemoteException;

// Calculate the power of a numberpublic BigInteger power ( int num1, int num2)

throws RemoteException;}

Our interface extends java.rmi.Remote, which indicates that this is a remote service. We provide method definitions for our two methods (square and power), and the interface is complete. The next step is to implement the interface, and provide methods for the square and power functions.

Page 9: remote method invocation

Implementing the interface

Implementing the interface is a little more tricky - we actually have to write the square and power methods! Don't worry if you're not sure how to calculate squares and powers, this isn't a math lesson. The real code we need to be concerned about is the constructor and main method.

We have to declare a default constructor, even when we don't have any initialization code for our service. This is because our default constructor can throw a java.rmi.RemoteException, from its parent constructor in UnicastRemoteObject. Sound confusing? Don't worry, because our constructor is extremely simple.

    public PowerServiceServer () throws RemoteException    {        super();    }

Our implementation of the service also needs to have a main method. The main method will be responsible for creating an instance of our PowerServiceServer, and registering (or binding) the service with the RMI Registry. Our main method will also assign a security manager to the JVM, to prevent any nasty surprises from remotely loaded classes. In this case, a security manager isn't really needed, but in more complex systems where untrusted clients will be using the service, it is critical.

    public static void main ( String args[] ) throws Exception    {        // Assign a security manager, in the event that dynamic       // classes are loaded

Page 10: remote method invocation

       if (System.getSecurityManager() == null)            System.setSecurityManager ( new RMISecurityManager() );

       // Create an instance of our power service server ...       PowerServiceServer svr = new PowerServiceServer();

       // ... and bind it with the RMI Registry       Naming.bind ("PowerService", svr);

       System.out.println ("Service bound....");    }

Once the square and power methods are added, our server is complete. Here's the full source code for the PowerServiceServer.

import java.math.*;import java.rmi.*;import java.rmi.server.*;

//// PowerServiceServer//// Server for a RMI service that calculates powers//public class PowerServiceServer extends UnicastRemoteObjectimplements PowerService{ public PowerServiceServer () throws RemoteException { super(); }

// Calculate the square of a number public BigInteger square ( int number ) throws RemoteException { String numrep = String.valueOf(number); BigInteger bi = new BigInteger (numrep);

Page 11: remote method invocation

// Square the number bi.multiply(bi);

return (bi); }

// Calculate the power of a number public BigInteger power ( int num1, int num2) throws RemoteException { String numrep = String.valueOf(num1); BigInteger bi = new BigInteger (numrep);

bi = bi.pow(num2);return bi;

}

public static void main ( String args[] ) throws Exception { // Assign a security manager, in the event that dynamic

// classes are loaded if (System.getSecurityManager() == null) System.setSecurityManager ( new RMISecurityManager() );

// Create an instance of our power service server ... PowerServiceServer svr = new PowerServiceServer();

// ... and bind it with the RMI Registry Naming.bind ("PowerService", svr);

System.out.println ("Service bound...."); }}

Writing a RMI client

What good is a service, if you don't write a client that uses it? Writing clients is the easy part - all a client has to do is call the registry to obtain a reference to the remote object, and call its methods. All the underlying network communication is hidden from view, which makes RMI clients simple.

Page 12: remote method invocation

Our client must first assign a security manager, and then obtain a reference to the service. Note that the client receives an instance of the interface we defined earlier, and not the actual implementation. Some behind-the-scenes work is going on, but this is completely transparent to the client.

    // Assign security manager    if (System.getSecurityManager() == null)    {        System.setSecurityManager   (new RMISecurityManager());    }

    // Call registry for PowerService    PowerService service = (PowerService) Naming.lookup        ("rmi://" + args[0] + "/PowerService");

To identify a service, we specify an RMI URL. The URL contains the hostname on which the service is located, and the logical name of the service. This returns a PowerService instance, which can then be used just like a local object reference. We can call the methods just as if we'd created an instance of the remote PowerServiceServer ourselves.

// Call remote methodSystem.out.println    ("Answer : " + service.square(value));

        // Call remote method        System.out.println    ("Answer : " + service.power(value,power));

Writing RMI clients is the easiest part of building distributed services. In fact, there's more code for the user interface menu in the client than there is for the RMI components! To keep things simple, there's no data validation, so be careful when entering numbers. Here's the full source code for the RMI client.

import java.rmi.*;import java.rmi.Naming;import java.io.*;

////// PowerServiceClient

Page 13: remote method invocation

////public class PowerServiceClient {

public static void main(String args[]) throws Exception{

// Check for hostname argumentif (args.length != 1){

System.out.println("Syntax - PowerServiceClient host");System.exit(1);

}

// Assign security managerif (System.getSecurityManager() == null){

System.setSecurityManager(new RMISecurityManager());

}

// Call registry for PowerServicePowerService service = (PowerService)

Naming.lookup("rmi://" + args[0] + "/PowerService");

DataInputStream din = new DataInputStream (System.in);

for (;;){

System.out.println ("1 - Calculate square");System.out.println ("2 - Calculate power");System.out.println ("3 - Exit"); System.out.println();System.out.print ("Choice : ");

String line = din.readLine();Integer choice = new Integer(line);

int value = choice.intValue();

Page 14: remote method invocation

switch (value){case 1: System.out.print ("Number : "); line = din.readLine();System.out.println(); choice = new Integer (line); value = choice.intValue();

// Call remote method System.out.println ("Answer : " + service.square(value));

break;case 2: System.out.print ("Number : "); line = din.readLine(); choice = new Integer (line); value = choice.intValue();

System.out.print ("Power : "); line = din.readLine(); choice = new Integer (line); int power = choice.intValue();

// Call remote method System.out.println

("Answer : " + service.power(value, power));

break;case 3: System.exit(0);default : System.out.println ("Invalid option");break;}

}}

}

Running the client and server

Page 15: remote method invocation

Our example was extremely simple. More complex systems, however, might contain interfaces that change, or whose implementation changes. To run this article's examples, both the client and server will have a copy of the classfiles, but more advanced systems might share the code of the server on a webserver, for downloading as required. If your systems do this, don't forget to set the system propertyjava.rmi.server.codebase to the webserver directory in which your classes are stored!

You can download all the source and class files together as a single ZIP file. Unpack the files into a directory, and then perform the following steps.

1. Start the rmiregistry

To start the registry, Windows users should do the following (assuming that your java\bin directory is in the current path):-

start rmiregistry

To start the registry, Unix users should do the following:-

rmiregistry &

2. Compile the server

Compile the server, and use the rmic tool to create stub files.

3. Start the server

From the directory in which the classes are located, type the following:-

java PowerServiceServer

4. Start the client

Page 16: remote method invocation

You can run the client locally, or from a different machine. In either case, you'll need to specify the hostname of the machine where you are running the server. If you're running it locally, use localhost as the hostname.

java PowerServiceClient localhost TIP - If you running the client or server with JDK1.2, then you'll need to change the security settings. You'll need to specify a security policy file (a sample is included with the source code and classes) when you run the client and server.

The following changes should be made when running the server

java -Djava.security.policy=java.policy PowerServiceServer

The following changes should be made when running the client

java -Djava.security.policy=java.policy PowerServiceClient localhost