E N D
Java RMI Introduction to RMI
Warning • This course is very volatile. Software is upgraded every semester. You should not assume that an example in the presentation is complete, or that it will work in the present environment. It is best to get your code examples from the Sun Java tutorials and modify them to work. Use the lectures to understand the general principles.
Java • Java is a general purpose Object-Oriented language • Java provides a number of features that support development of GUI applications and client/server applications over local and wide area networks (RMI and JDBC).
Remote Method Invocation (RMI) • RMI is a distributed computing technology • RMI enables networked application collaboration via remote method proxies • Interfaces implemented by the server object are instantiated in clients, where its methods are invoked as proxies to the server’s. • RMI services are available through the java.rmi, java.rmi.server, and java.rmi.registry packages
Key RMI Participants RMI Registry 2 1 Java Client Java Server Client code 3 Server Implementation 7 5 Remote Interface Remote Interface 4 6 Network
High-Level RMI Sequence • Server registers its interface in the RMI registry • Client queries registry for remote interface • Client implementation invokes interface object • The interface’s inherited classes “marshal” invocation parameters to network packets • The Server implements the interface’s methods • The Server returns its result to the network • The Client is issued the result
The Remote Interface (1) • Care must be taken in designing remote interfaces • Consider how to best balance computation and communication between nodes • Many calls to remote methods with small argument sizes is network inefficient • Few calls to remote methods with heavy computational needs incurs client latency
The Remote Interface (2) method computation time sluggish client, burdened server balanced client and server responsive client, underutilized server remote message size
The Remote Interface (3) • The interface extends the java.rmi.Remote interface • The interface must be public • An example interface public interface MyIntf extends Remote
Interface Methods (1) • The interface’s methods: • Not all parameters and return types are remote-able • The argument’s class or type must be “serializable” • A class is serializable if it implements the java.io.Serializable interface • The method must declare java.rmi.RemoteException in its throws clause
Interface Methods (2) • An example method declaration: public Boolean MyMethod (int Key) throws RemoteException;
The Remote Server (1) • The remote interface needs to be embedded in a server class so that its implementation can be defined • The Server class extends the java.rmi.server.UnicastRemoteObject and implements the user-defined interface • example: public class Server extends UnicastRemoteObject implements MyIntf
The Remote Server (2) • Constructors for remote objects must provide a default constructor that calls super() • All methods, including the constructor, must declare java.rmi.RemoteException in its throws clause • Example: Server() throws RemoteException { super(); }
The Remote Server (3) • Implement the remote interface’s methods • As before, all methods must throw RemoteException • Example: public Boolean MyMethod (int Key) throws RemoteException { method implemenetation here… }
The Remote Server (4) • The remote class is instantiated, either via a static main() method, or from some other class to execute. • The remote object typically requires a security manager to ensure that any classes being transferred to it (via its method calls for example) are valid. • The remote object need to be registered in the RMI registry so it can be located by clients.
The RMI Registry (1) • The RMI registry is a service that typically runs on the server’s node. It is used to help the client find the remote object’s reference so that it can invoke its methods. • The server registers itself with the RMI registry by giving itself a “well-known-name”
The RMI Registry (2) • Registration of the server object is done via the java.rmi.Naming class and its bind() or rebind() methods. • Example: Server server = new Server(); Naming.rebind(“MyServer", server); • This process makes the server object reference available to clients.
The RMI Registry (3) • To bind to a different protocol port, for example 2001, use: Naming.rebind(“//afsXX.njit.edu:2001/MyServer", server);
The Security Manager (1) • Security manager guarantees that the classes that get loaded perform only allowed operations. • If no security manager is specified, no class loading, by RMI clients or servers, is allowed, aside from what can be found in the local CLASSPATH. • A security manager is required in any JVM that needs to download code, and RMI clients need to download RMI stubs (as well as any other custom classes or interfaces needed to communicate with the RMI server).
The Security Manager (2) • Creating a policy file for the security manager • The server requires a policy file that is provided by the command-line invocation of the JVM to declare the process’ privileges • Example: grant { permission java.net.SocketPermission “hostname:1024-65535","connect,accept"; permission java.net.SocketPermission “hostname:80", "connect"; };
The Client (1) • The client needs to find the RMI registry so that it can locate remote-able objects. • After finding the registry, it can search for a specific object by the name it was registered with by the server. • The RMI registry finds the object reference of the named object, and returns it to the client. • The client invokes methods on the remote object reference.
The Client (2) • Find an RMI Registry service • Use the java.rmi.registry.LocateRegistry class to locate the registry with the getRegistry() method. • getRegistry can be called with a hostname if it is located on a node different than that the client is running. Example: Registry registry = LocateRegistry.getRegistry(hostname);
The Client (3) • To locate a specific object in the registry, one uses the Registry method lookup(). • Pass the name of the object to the lookup method. Example Server server = (Server)registry.lookup(“MyServer"); • The type needs to be casted to the server’s type as shown here (Server)
The Client (3) • The client can now make remote object reference method calls. • Exceptions need to be caught. • Example: try { server.MyMethod(keyValue); } catch (IOException e) { …; } catch (Exception e) { …; }
Running the Registry, Server, and Client • The RMI registry needs to be running first to be able to both accept registrations from servers and queries from clients. • Servers need to be running before the client (some advanced uses of the registry allow automatic server starting). • Finally, clients can be started.
Starting the RMI Registry • Starting the registry on a UNIX server: rmiregistry & • Starting on Windows: start rmiregistry • To start on a port other than the default port of 1099; for example port 2001: rmiregistry 2001 &
Starting the Server and Client • Need to supply a command line directive to indicate the security policy file. • java -Djava.security.policy=policy Server • java -Djava.security.policy=policy Client
Tools to examine your network messages • You can look at the messages you are sending across the network. • If you are using Eclipse with the RMI plug-in, it has a tool called RMI spy. • If you are passing a message across a network your laptop is logged on to, you can use Wire Shark. Note that if you are doing both your client and server on the University Computer Systems, you might not be able to use a network sniffer.
Bringing it all Together… • What follows is an example RMI client-server application that demonstrates the previous concepts. • The application is an emulated biometric authentication system. • Purpose is to read a user’s eye image and compare it to a database to see if the user has access privileges to the server.
Key Actions of the System • An image of the user’s eye is presented to a Client for processing • The eye image is encoded by an algorithm to create a signature • The Client passes the signature to the Server via a Java Remote Method Invocation • A Server listens for remote client requests to be authenticated. Upon reception, the Server compares the offered signature to those in its database. If there is a high correlation (≥ 95%), the user is granted access
Key Actions of the System (2) • Three representative eye images are used to denote “trusted” users of the system • Eye images are encoded by a radial signature algorithm • The signatures derived from the images are stored in an array within the Server for comparison • Validation requests are either accept or denied based on the comparison results of step 4
Eye Signature Algorithm (1) • To authenticate the eye, a signature is derived from its image • The signature of the Client’s eye is compared against a database • Because the image of the Client and its image on the server might be slightly different, some “fuzziness” is necessary in the evaluation to allow close, but not perfect matches
Eye Signature Algorithm (2) • For this demo, a simple eye signature algorithm radially samples the eye image as shown. • 500 samples are taken around the eye image. • Samples are stored in an int[] array.
The Remote Interface (1) • Let’s assume this Server is to serve many Clients. • How should the load be distributed? • Deriving a signature from the eye image requires image processing which can be expensive. • We choose to balance the compute and communications overhead by processing the eye image at the Client and only send its signature to the Server instead of the whole image.
The Remote Interface (2) • The interface shall transport an eye signature as an integer array to the Server for authentication • The Validation.java interface file: package cs633rmi; import java.rmi.*; public interface Validation extends Remote { public Boolean Validate (int[] sig) throws RemoteException; }
Image Processing (1) • An Image class is created to aid both the Client and Server classes. • This Image class can derive and store eye signatures, and performs the scoring function to compare eye images. • The code for the Image.java file follows.
Image Processing (2) package cs633rmi; import java.awt.image.*; import java.io.*; import javax.imageio.*; import java.lang.Math.*; public class Image { final int NUM_EYES = 3; final int NUM_SAMPLES = 500;
Image Processing (3) BufferedImage[] img = new BufferedImage[NUM_EYES]; int[][] signature = new int[NUM_EYES][NUM_SAMPLES]; // Initialization method public void Init() { // Initialize array elements for (int i=0; i<NUM_EYES; i++) { img[i] = new BufferedImage(100, 100, BufferedImage.TYPE_BYTE_GRAY); } }
Image Processing (4) public void LoadDatabase() { try { img[0]=ImageIO.read(new File("eye1.jpg")); img[1]=ImageIO.read(new File("eye2.jpg")); img[2]=ImageIO.read(new File("eye3.jpg")); } catch (IOException e){System.out.println(e);} // Analyze eye and derive its "signature". for (int i=0; i<NUM_EYES; i++) { signature[i] = DeriveEyeSignature(img[i]); } }
Image Processing (5) public int[] DeriveEyeSignature(BufferedImage eye) { // Find center of the image. int cx = eye.getWidth(null)/2; int cy = eye.getHeight(null)/2; int x, y, sample; double r = 0.0; double theta = 0.0; int[] sig = new int[NUM_SAMPLES];
Image Processing (6) // This loop is the radial sampler. for (int count=0; count<NUM_SAMPLES; count++) { r=r + 0.25; theta = theta + 0.075; x=(int)(r*java.lang.Math.cos(theta)+cx); y=(int)(r*java.lang.Math.sin(theta)+cy); // Sample, and mask to byte-width. sample = eye.getRGB(x, y) & 0xFF; sig[count++] = sample; } return(sig); }
Image Processing (7) public double[] Score(int[] sig) { double tmp_score; double score[] = new double[NUM_EYES]; for (int i=0; i<NUM_EYES; i++) { tmp_score = 0.0; for (int j=0; j<NUM_SAMPLES; j++) { if (java.lang.Math.abs(sig[j]- signature[i][j])<13) tmp_score++; } score[i]=tmp_score/(double)(NUM_SAMPLES); } return(score); }
Image Processing (8) public int NumEyes() { // Returns the number of eyes. return NUM_EYES; } public int NumSamples() { // Returns the number of samples per eye. return NUM_SAMPLES; }
The Client (1) • For this demo, the Client reads an eye image from a file to emulate scanning a user’s eye. • The Client uses the java.imageio and java.awt.image packages to simplify graphics file reading. • The Client takes single command line argument for the hostname where the RMI registry is running. • The Client.java file code follows:
Client (2) package cs633rmi; import java.io.*; import javax.imageio.*; import java.awt.image.*; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import cs633rmi.Validation; public class Client {
Client (3) public static void main(String args[]) { if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); } try { Registry registry = LocateRegistry.getRegistry(args[0]); Validation v = (Validation) registry.lookup("Validator");
Client (4) Image img = new Image(); img.Init(); BufferedImage eye = new BufferedImage(100, 100, BufferedImage.TYPE_BYTE_GRAY); eye = ImageIO.read(new File(args[1])); // Derive this eye's signature. int [] signature = new int[img.NumSamples()]; signature = img.DeriveEyeSignature(eye);
Client (5) // Pass this signature to the remote server for authentication. // Perform the RMI call here… Boolean b = v.Validate(signature); if (b) System.out.println(“Authenticated."); else System.out.println(“Denied access."); }