Beruflich Dokumente
Kultur Dokumente
Overview
Remote Method Invocation (RMI) allows object methods calls between Java Virtual Machines (JVMs) [1]. As the state of distributed network system dictate, JVMs can be sited on separate computers. However, one JVM can call methods belonging to an object sited in another JVM. Methods are allowed to pass objects of different type even if the objects have never been encountered before by the remote virtual machine. Classes are allowed to be loaded dynamically and as required. The best scenario in which RMI comes handy is when developer, for example, called (A) writes a service that performs a certain task. He regularly maintains this service, adding new features and improving existing ones. Let us assume that a developer B wants to use the service provided by developer A. Logic will dictate that A should find a convenient way to update the service without B being affected [2]. Java RMI solution relays on its ability to dynamically load new classes. Developer B can let RMI handle updates automatically for him. Developer (A) normally advertises the new classes in a web directory, where RMI can obtain the new updates as they are required.
Figure [1] illustrates the connections the client will make when using RMI. Firstly, the client must contact an RMI registry, and request the name of the service [1]. Client won't know where the RMI services are located, but he knows enough to contact Server's registry. This will direct him to the service he wants to use.
In the real world Server's service updates regularly and Client doesn't have a copy of the updated class. This shouldnt be a problem, because the client automatically obtains the new subclass from a web server where the service and client share classes. The new class will be loaded into a memory, and the client will be ready to use them. This happens transparently for client and, from its side, no more code need to be written to obtain the class.
Writing an interface The first step should be taken to write rmiservice is to agree upon an interface. An interface is a description of the methods we will allow remote clients to invoke. In this service interface we will have one method. This method must be implemented by another lotteryImp class. Here's the source code for the service that will generate a set of lottery numbers. public interface lotteryNum
extends java.rmi.Remote { public String numberGenerator(int money) throws java.rmi.RemoteException; } Our interface extends java.rmi.Remote, which indicates that this is a remote service. Later, a definition will be provided for the method (numberGenerator()) to complete the interface. The next step is to implement the interface, and provide method for the lottery number generators function. Implementing the interface Class lotteryImp implements the numberGenerator of the interface lotteryNum. The declaration of the default constructor here allows the program to throw a java.rmi.RemoteException from its parent constructor in UnicastRemoteObject. public lotteryImp () throws RemoteException { super(); } There are three methods in the lotteryImp class and they are numberGenerator, arrayListToString and searchIt. numberGenerator is the service methods and it will be called by the client later while the others two are utility methods . arrayListToString converts the a list of integers to string and searchIt uses a separate list to check whether the random method generated the same number twice. import java.util.Random; import java.util.ArrayList; public class lotteryImp extends java.rmi.server.UnicastRemoteObject implements lotteryNum { // Implementations must have an explicit constructor // in order to declare the RemoteException exception public lotteryImp() throws java.rmi.RemoteException { super(); }
public String numberGenerator(int money) throws java.rmi.RemoteException { ArrayList rev = new ArrayList(); ArrayList<Integer> items = new ArrayList<Integer>(); while( money > 0){ items.clear(); for( int i = 0 ; i < 7; i++){ Random generator = new Random(); int lotNum = generator.nextInt(46) + 1; int checker = searchIt( items,lotNum); if (checker> 0){ System.out.println(checker); --i; } else{ if(i+1==7){ rev.add("\n"); } else{ items.add(lotNum); rev.add(lotNum); rev.add(" "); } }//end of first if
String str = arrayListToString(rev); return str; } public static String arrayListToString(ArrayList arraylist) { StringBuilder arraylistTostr = new StringBuilder(); if (arraylist.size() > 0) { arraylistTostr.append(arraylist.get(0)); for (int i=1; i<arraylist.size(); i++) { arraylistTostr.append(arraylist.get(i)); } } return arraylistTostr.toString(); }//end of method arrayListToString public static int searchIt(ArrayList<Integer> arr , int lotNum){ int n = 0; for(int i=0; i<arr.size(); i++) if(arr.get(i)==lotNum) return i; return -1; }//end of search }
The first parameter represents the location and the name of URL that tells the callers the location of the remote service. Also, notable that the binding does not involves naming a protocol for data transmission. All we need to do is to change the value of the localhost to the IP address of the server machine. The default port number 1099 is not necessary to be stated here for the RMI to complete the running of the process. However, specifying the port number is a must when the registry is not running in a default port. The second parameter is a reference to where the object is implemented and will be used to invoke remote methods. Once an object is sent out, the RMI runtime environment starts a process of replacing a reference to the remote object's stub for the real remote object reference that is defined by the c parameter. When a client links up with a server's registry, the stub will be replaced with the actual implementation of the object and then using the same mechanism it will be returned to the client.
public lotteryServer() { try { lotteryNum c = new lotteryImp(); Naming.rebind("rmi://localhost:1099/lotteryService", c); } catch (Exception e) { System.out.println("Trouble: " + e); } } public static void main(String args[]) { new lotteryServer(); } }
public class lotteryClient { public static void main(String[] args){ String money = JOptionPane.showInputDialog("How much you want spent on lottery tickets"); int num = Integer.parseInt(money); try { lotteryNum lottery = (lotteryNum) Naming.lookup("rmi://localhost/lotteryService"); String str = lottery.numberGenerator(num); JOptionPane.showMessageDialog(null,"Here your numbers \n" +str, "Lottery ticket",JOptionPane.PLAIN_MESSAGE); }
System.out.println(); System.out.println("RemoteException"); System.out.println(re); } catch (NotBoundException nbe) { System.out.println(); System.out.println("NotBoundException"); System.out.println(nbe); } catch (java.lang.ArithmeticException ae) { System.out.println(); System.out.println("java.lang.ArithmeticException"); System.out.println(ae); } }
} Running the client and server Using the jdk1.6.0_21 command prompt you can the program as the following:
1. Compile the interface lotteryNum and its implementation lotteryImp
3.
start rmiregistry
4. Compile and start the server
Javac lotteryClient java lotteryClient 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. Summary Java RMI is an excellent system for calling up methods of remote objects. RMI methods are allowed to pass objects of different type even if the objects have never been encountered before by the remote virtual machine. RMI allows the code that defines the behaviour and the code that implements the behaviour to remain separate and to run on separate JVMs. This fits nicely with the needs of a distributed system where clients are concerned about the definition of a service and servers are focused on providing the service.
Testing
2- Java RMI
brimponn@lsbu.ac.uk