INTRODUCTION:Remote method invocation allows applications to call object methods located remotely, sharing resources and processing load across systems. Unlike other systems for remote execution which require that only simple data types or defined structures be passed to and from methods, RMI allows any Java object type to be used - even if the client or server has never encountered it before.
RMI allows both client and server to dynamically load new object types as required.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.DESIGN:In order to understand the design of the RMI program, it is important to comprehend the way that RMI functions, a brief look at the RMI architecture will help explain the design of our program.RMI architecture:The server must first bind its name to the registryThe client lookup the server name in the registry to establish remote references.The Stub serializing the parameters to skeleton, the skeleton invoking the remote method and serializing the result back to the stub.Stub and Skeleton:A client invokes a remote method; the call is first forwarded to stub.The stub is responsible for sending the remote call over to the server-side skeletonThe stub opening a socket to the remote server, marshalling the object parameters and forwarding the data stream to the skeleton.A skeleton contains a method that receives the remote calls, unmarshalls the parameters, and invokes the actual remote object implementation.Flow Diagrams:The following will represent:? The RMI Client side flow diagram? The RMI Server side flow diagramIMPLEMENTATION:RMIFile INTERFACE:/*Import package java.rmi*/import java.rmi.*;/*Define public interface that is an extension of java.rmi.Remote*/public interface RMIFile extends Remote{/*Declare a read() method that takes two arguments and throws a RemoteException*/String read(int linenum, char passwd) throws RemoteException;}RMIFileImpl:/*Import the following packages to be used in the program*/import java.rmi.*;import java.rmi.server.*;import java.io.*;/*Declare a public class that extends a UnicastRemoteObjec and implements the RMIFile*/public class RMIFileImpl extends UnicastRemoteObject implements RMIFile{/*Declare a static String object and assign to "localhost"*/public static final String Host ="localhost";/*Define a constructor that calls super() and throws a RemoteException*/public RMIFileImpl() throws RemoteException{super();}/*Implement the read() method defined in the remote interface*/public String read(int linenum, char passwd) throws RemoteException{try{/*Instantiate an String object, and set it to null*/String ast = null;/*open a file for reading*/FileReader fr=new FileReader("hello.txt");/*wrap the filereader to a bufferedreader*/BufferedReader frb = new BufferedReader(fr);/*read one line*/for(int i=0; i<linenum; i++){ast=frb.readLine();}/*Print the message before encryption*/System.out.println("Before Encryption:"+ast);/*Encrypt the message*/char[] aa=ast.toCharArray();for(int i=0;i<aa.length;i++)aa[i]=(char)(aa[i]^passwd);/*Instantiate a String object and store in it the encrypted message stored in the aa array*/String ooo=new String(aa);/*Print the message on the screen after the encryption*/System.out.println("After Encryption:"+ooo);/*Return the content of the ooo String to requesting Client*/return ooo;/*Catch the FileNotFoundException and print an error message on the screen*/}catch(FileNotFoundException e){System.out.println("file not found");System.exit(1);}/*Catch the IOException and print an error message on the screen*/catch(IOException e){System.out.println(e);System.exit(1);}/*Return a null value*/return null;}}RMIServer:/*Import the following packages to be used in the program*/import java.rmi.*;import java.rmi.server.*;import java.io.*;/*Declare a public class called RMIServer*/public class RMIServer{/*Declare a static String object and assign to "localhost"*/public static final String Host ="localhost";/*Define the main method in program which takes a String array as an argument and throws an Exception*/public static void main(String args[]) throws Exception{try{/* Create an instance of the RMIFileImpl*/RMIFileImpl temp = new RMIFileImpl();/*Register remote object with RMI registry*/Naming.rebind("rmi://" +Host+"/RMIFile",temp);/*Catch the IOException and print an error message on the screen*/}catch(Exception e){System.err.println(e);System.exit(1);}}}RMIClient:/*Import the following packages to be used in the program*/import java.rmi.*;import java.io.*;/*Define an RMIClient public class*/public class RMIClient{/*Declare a static String object and assign to "localhost"*/private static final String Host = "localhost";/*Define the main method in program which takes a String array as an argument and throws an Exception*/public static void main(String args[]){/*If the length of the args array is not equal to two arguments then a error message is printed on the screen*/if (args.length !=2){System.err.println("usage: java MyApp <linenumber<character>");System.exit(1);}try{/*Convert the first received argument from a String to an integer*/int linenum = Integer.parseInt(args[0]);/*Create an array in which all the converted Strings to characters are stored*/char aaa[]=args[1].toCharArray();/*Select the first element of the aaa array and store it in the passwd object*/char passwd =aaa[0];/*If linenum is over 10, then print error message on the screen*/if (linenum>10){System.err.println("the number should not be over 10");System.exit(1);}/*Construct a link object used to look up a RMIFile remote object*/RMIFile link = (RMIFile)Naming.lookup("rmi://" +Host +"/RMIFile");/*look up the remote object in the remote host's registry*/String result1 = link.read(linenum, passwd);/*Decrypt the message received from the server*/char[] bb = result1.toCharArray();for(int i=0;i;bb.length;i++)bb[i]=(char)(bb[i]^passwd);/*Create a String object in which to store the message after the decryption*/String kkk=new String(bb);/*Display the message before decryption*/System.out.println("Before Decryption:" +result1);/*Display the message after decryption*/System.out.println("After Decryption:"+kkk);}/*Catch the Exception error and print an error message, and exit the system*/catch (Exception e){System.out.println("The first argument should be a number and the second argument should be a character");System.out.println(e);System.exit(1);}}}TESTING:A testing procedure was followed to show the program is running and also highlight the error handling procedure implemented in the process:To show the program running, we first compile all the programs including, RMIFile, RMIFileImpl, RMIClient, RMIServer.The following steps are followed in order to run the program:1) generate the stub and skeleton:2) Start the RMI registry:3) Run the RMIServer:When the RMIServer is prompted by the client to return a file, it responds in the following manner showing the message before encryption and after encryption:4) We then run the RMIClient program and give two arguments a number and a letter to encrypt the message with, the file is then returned in an encrypted format, and it gets decrypted and displayed on the screen.If a different letter is entered by the user, then the encryption changes accordingly:If a different number is entered, then the file with the correct number gets extracted and displayed on the screen:ERROR HANDLING:The user might provide a wrong input, in which case the program should be able to handle such cases and display an error message, this section will cover such occurrences.1) If the user provides a character instead of a number in the first argument then the following message is displayed and the program is stopped:2) If the user enters a number over 10, then the following message is displayed, prompting the user to enter a number that is not over than 10.