Compiling and Running the Program in JAVA

1. COMPILING THE PROGRAM

Suppose the server application is developed in the directory E:\Net\rmi\caicuiator\server of a computer having IP address 172.16.5.81. Hereafter, we shall refer to this directory as server_home. Now, put server-side files in server_home as shown in Figure 14.7: (i)

Assume that the client application is developed in the directory E:\Net\rmi\caicuiator\ciient of another computer. We shall refer to this directory as ciient_home. Now, put client-side files in ciient_home as shown in Figure 14.7: (ii).

1.1. Compiling Server

Open a terminal and go to the directory server_home. This directory contains three files, Caicuiator.java, SimpieCaicuiator.java and CaicuiatorServer.java. Use javac command to compile these Java source files as follows:

javac *.java

This generates the class files Calculator.class, SimpleCalculator.class and CalculatorServer. ciass

1.2. Compiling Client

Go to the directory ciient_home. The Calculator.class generated in server_home directory is needed by the client to develop its own applications. Get this class file from server_home directory and put it in ciient_home. Alternatively, you can put the Caicuiator.java file in ciient_home and generate the class file using the following command

javac Caicuiator.java

Now, give the following command to compile client-side source file.

javac CaicuiatorCiient.java

This generates a class file CaicuiatorCiient.ciass

2. GENERATING STUB CLASSES

Java 5.0 and later releases add support for the dynamic generation of stub classes at runtime, obviating the need to use the Java RMI stub compiler, rmic, to pregenerate stub classes for remote objects. Note that rmic must still be used to pregenerate stub classes for remote objects that need to support clients running on earlier versions.

When remote object is exported (using the constructors or static exportobject() methods of the classes java.rmi.server.UnicastRemoteObject or java.rmi.activation.Activatable) and a pregenerated stub class for the remote object is not found, the remote object’s stub will be a java. lang.reflect.Proxy instance (whose class is dynamically generated) with a java.rmi.server. RemoteObjectInvocationHandier as its invocation handler. A detail about enhancements that have been incorporated in the current version of Java can be found in http://docs.oracie.com/ javase/1.5.0/docs/guide/rmi/reinotes.htmi.

However, if a stub class is really needed, use the following command to generate it:

rmic SimpieCaicuiator

3. RUNNING THE PROGRAM

Before starting the server application, we need to start an object registry. In Java RMI, it is started using the rmiregistry command. So, open a terminal, go to the server_home directory and type the following command:

start rmiregistry

The command opens new windows and starts the object registry application on the default port 1099. Note that rmiregistry needs Caicuiator.ciass file when a Calculator object is registered. So, rmiregistry should be started from a directory that contains Caicuiator.ciass file. However, RMI has techniques for loading class dynamically, which will be illustrated in a separate application in detail.

3.1. Start Server

Give the following command to start the server:

java CaicuiatorServer

It produces a sample output as shown in Figure 14.8:

3.2. Start client

Go to the ciient_home directory and give the following command to start the client:

java CalculatorClient 172.16.5.81

3.3. Understanding object Registry

The registry is essentially an application for the server to register services it offers and a place for clients to query for those services. Let us now understand how this application functions.

When a registry is started using rmiregistry command or Registry.createRegistry() method, it creates a ServerSocket object and listens for incoming connection. If a client program invokes lookup() method, it makes a socket connection to the remote registry application and sends the name of the object specified as argument through the connection. The remote registry finds the stub with this name and sends this object over the network back to the client using object serialization. The lookup() method, upon receiving the serialized data, reconstructs the object and finally returns it to the caller. The returned object is the client-side proxy of the server object and knows how to communicate with the object through the server-side proxy. So, if we can somehow create an instance of the stub at the client side, invoking a method on the remote object becomes possible readily.

In this section, we shall develop a simple registry that behaves as described above. The following is the complete source code of this registry store in a file SimpleRegistry.java.

import java.rmi.*;

import java.io.*;

import java.net.*;

import java.util.*;

public class SimpleRegistry implements Runnable

{

int port;

Hashtable objects = new Hashtable();

public SimpleRegistry(int prt) {

this.port = prt; new Thread(this).start();

}

public SimpleRegistry()

{

this(678 9);

}

public void rebind(Remote o, String name)      {

objects.put(name, o);

}

public static Object lookup(String host, int port, String name) throws

IOException, ClassNotFoundException {

Socket clientEnd = new Socket(host, port);

PrintWriter toServer = new PrintWriter(clientEnd.getOutputStream(), true);

toServer.println(name);

ObjectInputStream in = new ObjectInputStream(clientEnd.getInputStream());

return in.readObject();

}

public void run()

{

try {

ServerSocket serverSocket = new ServerSocket(port);

while(true)

{

Socket serverEnd = serverSocket.accept();

BufferedReader fromClient = new BufferedReader(new

InputStreamReader(serverEnd.getInputStream()));

String name = fromClient.readLine();

Remote o = (Remote)objects.get(name);

ObjectOutputStream oos = new

ObjectOutputStream(serverEnd.getOutputStream());

oos.writeObject(o);

}

}catch(Exception e) {}

}

}

Now modify the calculator server as follows:

//Registry registry = LocateRegistry.getRegistry();

//registry.rebind(name, stub);

SimpleRegistry reg = new SimpleRegistry();

reg.rebind(stub, name);

The original statements in the server are shown in the comment line. Also modify the calculator client as follows:

//Registry registry = LocateRegistry.getRegistry(args[0]);

//Calculator cal = (Calculator)registry.lookup(name);

Calculator cal = (Calculator)SimpleRegistry.lookup(args[0],

Integer.parseInt(args[1]), name);

The original statements in the client are shown in the comment line. Compile and run the application as discussed earlier. Note the calculator server creates a SimpleRegistry. So, a separate rmiregistry application is not needed. A sample output is shown in Figure 14.10:

3.4. Using RMI URL

In our calculator example, server exports and registers a remote object explicitly using a tedious procedure. The client also gets a reference to the remote object using a long method. Java RMI provides a simple addressing mechanism, known as RMI URL, which may be used by the server as well as the client for the same purpose.

The server application creates an object and registers it to the RMI registry using the static rebind() method of java.rmi.Naming class. The server must specify the port number of RMI registry application and the IP address or name of the computer where it runs. The server must also specify a logical name by which the object will be known to clients. Clients use this name to get a reference to this object.

The entire information may be encapsulated using RMI URL. It is similar to the HTTP URL except that it uses “rmi” as the protocol name. It takes the following form:

rmi://host:[port]/objectName

The host is the IP address or Fully Qualified Domain Name (FQDN) of the computer where the RMI registry runs. The optional port is the port number of the RMI registry. The default port number is 1099. The objectName is a logical name of the object. For example, if RMI registry runs in a computer having IP address 172.16.5.81 on port 2000, and object name is calculator, the RMI URL for this object will be as follows:

protocol host port name

If RMI registry runs on default port (1099), the above URL reduces to

rmi://172.16.5.81/calculator

If RMI registry and server run on the same computer, the above URL further reduces to

calculator

Since, Java RMI only supports to run RMI registry and server on the same computer, the URL of our remote object is simply calculator.

Now, create an object and register it using the Naming.rebind() method as follows:

String url = “calculator”;

SimpleCalculator calculator = new SimpleCalculator();

Naming.rebind(url, calculator);

The java.rmi.Naming.rebind() method, essentially parses the uri,gets a reference to the registry using LocateRegistry.getRegistry() method and finally calls rebind() method on this registry. A code snippet of java.rmi.Naming.rebind() is given below:

package java.rmi;

import java.rmi.registry.*;

//…

public final class Naming

{

//.

public static void rebind(String name, Remote obj)

throws RemoteException, java.net.MalformedURLException

{

ParsedNamingURL parsed = parseURL(name);

Registry registry = getRegistry(parsed); if (obj == null)

throw new NullPointerException(”cannot bind to null”);

registry.rebind(parsed.name, obj);

}

//…

}

Since java.rmi.Naming.rebind() method expects second argument as Java.rmi.Remote type object, the class definition of simpieCaicuiator needs to be modified slightly in this case as follows:

//SimpleCalculator.java import java.rmi.*;

import java.rmi.server.*;

public class SimpleCalculator extends UnicastRemoteObject implements Calculator

{

SimpleCalculator()throws RemoteException {}

public int add(int a, int b)

{

System.out.println(”Received: ” + a + ” and ” + b);

int result = a + b;

System.out.println(”Sent: ” + result);

return result;

}

}

The code that has been added is shown with bold face. Here is the modified source code of

CalculatorServer.Java.

//CalculatorServer.java

import java.rmi.*;

public class CalculatorServer

{

public static void main(String args[])

{

try {

String url = “calculator”;

SimpleCalculator calculator = new SimpleCalculator();

Naming.rebind(url, calculator);

System.out.println(”Calculator server ready…”);

}catch (Exception e) { e.printStackTrace(); }

}

}

The Naming.rebind() method registers the calculator object with the name “calculator” to the registry running on the same machine on the default port. You can now start the rmiregistry and server as before.

The client application can also make use of RMI URL to get a reference. We are assuming that the RMI registry will run on the default port. So, the URL of the remote object for the client looks like this:

String uri = “rmi://” + args[0] + “/calculator”;

The name of the object is “calculator”. The first command line argument args[0] is the IP address or Fully Qualified Domain Name (FQDN) of the server.

Caicuiator cai = (Caicuiator)Naming.lookup(url);

The code above contacts the RMI registry running in the computer specified by the command line argument and asks for the stub for the object, registered under the name calculator. The rest of the client code is the same. Compile the code and start the client application as before.

Source: Uttam Kumar Roy (2015), Advanced Java programming, Oxford University Press.

Leave a Reply

Your email address will not be published. Required fields are marked *