• Tidak ada hasil yang ditemukan

Implementation Details

Remote Method Invocation (RMI)

5.2 Implementation Details

The packages used in the implementation of an RMI client–server application are java.rmi , java.rmi.server and java.rmi.registry , though only the fi rst two need to be used explicitly. The basic steps are listed below.

1. Create the interface.

2. Defi ne a class that implements this interface.

3. Create the server process.

4. Create the client process.

Simple Example

This fi rst example application simply 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 realistic application, there would almost certainly be more methods and those methods would belong to some class (as will be shown in a later example). However, we shall adopt a minimalistic approach until the basic method has been covered. The required steps will be numbered as above…

1. Create the interface.

This interface should import package java.rmi and must extend interface Remote , which (like Serializable ) is a ‘tagging’ interface that contains no methods. The inter- face defi nition 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 RemoteException . The contents of this fi le are shown below.

import java.rmi.*;

public interface Hello extends Remote {

public String getGreeting() throws RemoteException;

}

2. Defi ne a class that implements this interface.

The implementation fi le should import packages java.rmi and java.rmi.server . The implementation class must extend class RemoteObject or one of RemoteObject ’s subclasses. In practice, most implementations extend subclass UnicastRemoteObject , since this class supports point-to-point communication using TCP streams. The implementation class must also implement our interface Hello , of course, by pro- viding an executable body for the single interface method getGreeting . In addition, we must provide a constructor for our implementation object (even if we simply give this constructor an empty body, as below). Like the method(s) declared in the interface, this constructor must declare that it throws a RemoteException . Finally, we shall adopt the common convention of appending Impl onto the name of our interface to form the name of the implementation class.

import java.rmi.*;

import java.rmi.server.*;

public class HelloImpl extends UnicastRemoteObject implements Hello {

public HelloImpl() throws RemoteException {

//No action needed here.

}

public String getGreeting() throws RemoteException {

return ("Hello there!");

} }

3. Create the server process.

The server creates object(s) of the above implementation class and registers them with a naming service called the registry . It does this by using static method rebind of class Naming (from package java.rmi ). 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 (as an argument of type Remote ).

The method establishes a connection between the object’s name and its refer- ence. Clients will then be able to use the remote object’s name 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, specifi es the name of the remote object’s host machine. For simplicity’s sake, we shall use localhost (which is what RMI assumes by default anyway). The default port for RMI is 1099, though we can change this to any other convenient port if we wish. The code for our server process is shown below and contains just one method: main . To cater for the various types of exception that may be generated, this method declares that it throws Exception .

import java.rmi.*;

public class HelloServer {

private static fi nal String HOST = "localhost";

public static void main(String[] args)

throws Exception {

//Create a reference to an //implementation object…

HelloImpl temp = new HelloImpl();

//Create the string URL holding the //object's name…

String rmiObjectName = "rmi://" + HOST + "/Hello";

//(Could omit host name here, since 'localhost' //would be assumed by default.)

//'Bind' the object reference to the name…

Naming.rebind(rmiObjectName,temp);

//Display a message so that we know the process //has been completed…

System.out.println("Binding complete…\n");

} }

4. Create the client process.

The client obtains a reference to the remote object from the registry. It does this by using method lookup of class Naming , supplying as an argument to this method the same URL that the server did when binding the object reference to the object’s name in the registry. Since lookup returns a Remote reference, this reference must be typecast into an Hello reference ( not an 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.

import java.rmi.*;

public class HelloClient {

private static fi nal String HOST = "localhost";

public static void main(String[] args) {

try {

//Obtain a reference to the object from the //registry and typecast it into the appropriate //type…

Hello greeting =

(Hello)Naming.lookup("rmi://"

+ HOST + "/Hello");

//Use the above reference to invoke the remote //object's method…

System.out.println("Message received: "

+ greeting.getGreeting());

}

catch(ConnectException conEx) {

System.out.println(

"Unable to connect to server!");

System.exit(1);

}

catch(Exception ex) {

ex.printStackTrace();

System.exit(1);

} } }

Note that some authors choose to combine the implementation and server into one class. This author, however, feels that the separation of the two probably results in a clearer delineation of responsibilities.

The method required for running the above application is provided in the next section.