CPT402 Software Architectures Lab1
RMI
Hello RMI
Introduction
- Client inputs its name
- Server simply responds with a hello message with
client’s name
- HelloRMI.rmiinterface contains code for remote interfaces
- HelloRMI.server contains code for server program
- HelloRMI.client contains code for client program
Implementation
Defining remote interfaces
- An object becomes remote by implementing a remote interface java.rmi.Remote; each method of the interface declares java.rmi.RemoteException in its throws clause.
package rmiinterface;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RMIInterface extends Remote{
String helloRMI(String clientName) throws RemoteException;
}
Implementing the remote server
-
An RMI server program needs to create the initial remote objects and export them to the RMI runtime, which makes them available to receive incoming remote invocations. This setup procedure can be either encapsulated in a method of the remote object implementation class itself or included in another class entirely.
The setup procedure should do the following:- Create and install a security manager
- Create and export one or more remote objects
- Register at least one remote object with the RMI registry (or with another naming service, such as a service accessible through the Java Naming and Directory Interface) for bootstrapping purposes
-
Any methods defined in the implementation class or defined in non-remote interfaces implemented by the class are not available to that receiver.
(In this example, the receiver of the reference to an instance of this RMIServer class would not see the RMIServer constructor, its main method, or its implementation of any methods of java.lang.Object.) -
Security Manager protects access to system resources from untrusted downloaded code running within the Java virtual machine.
A security manager determines whether downloaded code has access to the local file system or can perform any other privileged operations. -
If an RMI program does not install a security manager, RMI will not download classes (other than from the local class path) for objects received as arguments or return values of remote method invocations. This restriction ensures that the operations performed by downloaded code are subject to a security policy.
-
The static UnicastRemoteObject.exportObject method exports the supplied remote object so that it can receive invocations of its remote methods from remote clients. The second argument, an int, specifies which TCP port to use to listen for incoming remote invocation requests for the object. It is common to use the value zero, which specifies the use of an anonymous port. The actual port will then be chosen at runtime by RMI or the underlying operating system.
However, a non-zero value can also be used to specify a specific port to use for listening. Once the exportObject invocation has returned successfully, the ComputeEngine remote object is ready to process incoming remote invocations. -
The java.rmi.registry.Registry remote interface is the API for binding (or registering) and looking up remote objects in the registry.
-
The java.rmi.registry.LocateRegistry class provides static methods for synthesizing a remote reference to a registry at a particular network address (host and port). These methods create the remote reference object containing the specified network address without performing any remote communication.
-
The no-argument overload of LocateRegistry.getRegistry synthesizes a reference to a registry on the local host and on the default registry port, 1099. You must use an overload that has an int parameter if the registry is created on a port other than 1099.
package server;
import java.rmi.RemoteException;
import rmiinterface.RMIInterface;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
/**
* This class has a main method for setting up the server
* this class also implements interface, so can be used for a remote object
* @author colin
*/
public class RMIServer implements RMIInterface{
// server instancs, make it avaliable to clients
@Override
public String helloRMI(String clientName) throws RemoteException {
return "Hello "+clientName;
}
// this main method is used to start the RMI Server
// this method is not a remote method (cause it is static)
// setup procedure
public static void main(String[] args) throws RemoteException {
// Creating and Installing a Security Manager
// if (System.getSecurityManager()==null){
// System.setSecurityManager(new SecurityManager());
// }
// == rmiregistry& command on MacOS
LocateRegistry.createRegistry(1099);
try {
// initial remote object,
RMIInterface myHello = new RMIServer();
// Now we need export it to the RMI runtime
// to receive incoming remote invocations
// .exportObject might throw RemoteException
// returns a stub for the exported remote object
// ! the type of stub must be Interface
// because the stub only implements the remote interfaces
RMIInterface stub = (RMIInterface) UnicastRemoteObject.exportObject(myHello, 0);
// Registry: a simple remote object naming server
// get a reference to a registry on the local host
Registry registry = LocateRegistry.getRegistry();
// adds the name to the RMI registry running on the server.
String name = "Hello program";
registry.rebind(name, stub);
System.out.println("Server started");
} catch (Exception e) {
System.err.println("RMI Server exception:");
e.printStackTrace();
}
}
}
Implementing the clients
package client;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import rmiinterface.RMIInterface;
public class RMIClient {
public static void main(String[] args) {
// if (System.getSecurityManager()==null){
// System.setSecurityManager(new SecurityManager());
// }
try {
String name = "Hello program";
// get registry from a remote server
Registry registry = LocateRegistry.getRegistry("127.0.0.1",1099);
//get a reference of a remote object
RMIInterface myHellp = (RMIInterface)registry.lookup(name);
// invoke method of that remote object
String message = myHellp.helloRMI("Colin");
System.out.println(message);
} catch (Exception e) {
System.err.println("Client say hello exception");
e.printStackTrace();
}
}
}
Starting the application
IDE(NetBeans) Version
- Build project
- Start server:
- Run File (RMIServer)
- Start client:
- Run File (RMIClient)
Command Line(MacOS) Version
- Build project
- Start registry:
- rmiregistry& :This command has the same effect as the LocateRegistry.createRegistry(1099);
You can ignore this if you have createRegistry() in Java code. - Need to be executed in the same folder as your classes if classpath not set.
- rmiregistry& :This command has the same effect as the LocateRegistry.createRegistry(1099);
HelloRMI/build/classes$ rmiregistry&
[1] 1456
It will return its PID number.
HelloRMI/build/classes$ lsof -i | grep 1456
rmiregist 1456 colin 9u IPv6 0x9413eb7ad9360e ...
We can kill it like:
HelloRMI/build/classes$ kill -9 1456
- Start server:
HelloRMI/build/classes$ java HelloRMI.server.RMIServer
- Start client:
HelloRMI/build/classes$ java HelloRMI.client.RMIClient
If you installed a security manager in your program, you need have a server policy server.policy under the same folder as you class file.
grant codeBase "file:/Users/colin/Developer/java/HelloRMI/build/classes/" {
permission java.security.AllPermission;
permission java.net.SocketPermission "127.0.0.1:1099","connect,resolve";
};
And execut like this:
HelloRMI/build/classes$ java -Djava.security.policy=server.policy server.RMIServer
light-weight calculator system
Introduction
Functionalities provided by the server
- public int add(int a, int b);
- public int compare(int a, int b);
- a > b return 1
- a = b return 0
- a < b return -1
- public boolean equal(Group a, Group b);
- Class Group contains three int attributes x, y
and z
- Class Group contains three int attributes x, y
- RMIcalculator.rmiinterface contains code for remote interfaces
- RMIcalculator.server contains code for server program
- RMIcalculator.client contains code for client program
- RMIcalculator.bean contains helper classes
Implementation
Defining help classes
Passing Objects in RMI
- Arguments to or return values from remote methods can be of almost any type, including local objects, remote objects, and primitive data types. More precisely, any entity of any type can be passed to or from a remote method as long as the entity is an instance of a type that is a primitive data type, a remote object, or a serializable object, which means that it implements the interface java.io.Serializable.
package bean;
import java.io.Serializable;
public class Group implements Serializable{
int x;
int y;
int z;
public Group(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
}
Defining remote interfaces
package rmiinterface;
import bean.Group;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface CalInterface extends Remote{
public int add(int a, int b) throws RemoteException;
public int compare(int a, int b) throws RemoteException;
public boolean equal(Group a, Group b) throws RemoteException;
}
Implementing the remote server
This time, the implementation of remote Interface and the setup of the server are in two classes, hope it‘s easier to understand.
package server;
import bean.Group;
import java.rmi.RemoteException;
import rmiinterface.CalInterface;
public class CalClass implements CalInterface{
@Override
public int add(int a, int b) throws RemoteException {
return a+b;
}
@Override
public int compare(int a, int b) throws RemoteException {
return a>b ? 1 : a==b ? 0 : -1;
}
@Override
public boolean equal(Group a, Group b) throws RemoteException {
return a.getX()==b.getX() && a.getY()==b.getY()&& a.getZ()==b.getZ();
}
}
package server;
import java.rmi.RemoteException;
import rmiinterface.CalInterface;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
public class Server {
public static void main(String[] args) {
// if (System.getSecurityManager()==null){
// System.setSecurityManager(new SecurityManager());
// }
int portid = 1099;
try {
LocateRegistry.createRegistry(portid);
System.out.println("Using port: "+portid);
} catch (RemoteException ex) {
System.out.println("createRegistry Error, might be Port occupied:"+portid);
ex.printStackTrace();
}
String name = "my Calculator";
CalClass cal = new CalClass();
try {
CalInterface stub = (CalInterface)UnicastRemoteObject.exportObject(cal, 0);
Registry registry = LocateRegistry.getRegistry();
registry.rebind(name, stub);
System.out.println("Server started~");
} catch (RemoteException ex) {
ex.printStackTrace();
}
}
}
Implementing the clients
package client;
import bean.Group;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import rmiinterface.CalInterface;
public class CalClient {
public static void main(String[] args) {
// if (System.getSecurityManager()==null){
// System.setSecurityManager(new SecurityManager());
// }
try {
String name = "my Calculator";
Registry registry = LocateRegistry.getRegistry();
CalInterface myCal = (CalInterface)registry.lookup(name);
System.out.println("2+3 = "+myCal.add(2, 3));
System.out.println("2 compare 3: "+myCal.compare(2, 3));
System.out.println("2 compare 3: "+myCal.compare(3, 3));
System.out.println("2 compare 3: "+myCal.compare(3, 2));
Group a = new Group(1, 2, 3);
Group a2 = new Group(1, 2, 3);
Group b = new Group(3, 2, 1);
System.out.println("Group a & a2: "+myCal.equal(a, a2));
System.out.println("Group a & b: "+myCal.equal(a, b));
} catch (Exception e) {
System.err.println("Client calculator exception");
e.printStackTrace();
}
}
}