A distributed system is a program or set of programs that runs using more than one computing resource. Distributed computing covers a wide spectrum, from intra-process distributed applications , through intrasystem applications (such as a network client and server on the same machine), to applications where a client program and a server program run on machines far apart (such as a web application).
Distributed computing was around for a long time before Java. Some traditional distributed mechanisms include RPC (remote procedure call) and CORBA. Java adds RMI (Remote Method Invocation), its own CORBA support, and EJB (Enterprise JavaBeans) to the mix. At its simplest level, remote procedure call is the ability to run code on another machine and have it behave as much as possible like a local method call. Most versions of Unix use remote procedure calls extensively: Sun's NFS, YP/NIS, and NIS+ are all built on top of Sun's RPC. Windows NT implements large parts of the Unix DCE Remote Procedure Call and can interoperate with it. Each of these defines its own slightly ad hoc method of specifying the interface to the remote call. Sun's RPC uses a program called rpcgen, which reads a protocol specification and writes both the client and server network code. These are both Unix-specific;
they have their place, but aren't as portable as Java.
Java Remote Methods Invocation (RMI) is a type of remote procedure call that is network independent, lightweight, and totally portable, as it's written in pure Java.
CORBA is the Object Management Group's (OMG) Common Object Request Broker Architecture, a sort of remote procedure call for programs written in C, C++, Java, Ada, Smalltalk, and others to call methods in objects written in any of those languages. It provides a transport service called the Internet Inter-Orb Protocol (IIOP) that allows object implementations from different vendors to interoperate. There is now a version of RMI over IIOP, making it possible to claim that RMI is CORBA-compliant.
Enterprise JavaBeans (EJB) is a distributed object mechanism used primarily for building reusable distributed objects that provide both business logic and database storage. There are several types of EJBs, including session beans, which do something (a shopping cart bean is a good example) and entity beans, which represent something (usually the things stored in a database; in our shopping cart example, the entity beans would be the objects available for purchase).
Basic Steps: RMI
1. Define (or locate) the remote interface in agreement with the server.
2. Write server program.
3. Run rmic (Java RMI stub compiler) to generate the network glue.
4. Write the client.
5. Ensure that the RMI registry is running.
6. Start the server.
7. Run one or more clients.
6.2 Defining the RMI Contract
RMI procedures are defined using an existing Java mechanism: interfaces. An interface is similar to an abstract class, but a class can implement more than one interface. RMI remote interfaces must be subclassed from java.rmi.Remote and both the client and server must be in the same Java package. All parameters and return values must be either primitives (int, double, etc.), or implement Serializable (as do most of the standard types like String). Or they can also be Remote.
Figure shows the relationships between the important classes involved in an RMI implementation. The developer need only write the interface and two classes, the client application and the server object implementation. The RMI stub or proxy and the RMI skeleton or adapter are generated for us by the rmic program while the RMI Registry and other RMI classes at the bottom of the figure are provided as part of RMI itself. Next example is a simple RemoteDate getter interface, which lets us find out the date and time on a remote machine.
Example RemoteDate.java
package darwinsys.distdate;
import java.rmi.*;
import java.util.Date;
/** A statement of what the client & server must agree upon. */
public interface RemoteDate extends java.rmi.Remote {
/** The method used to get the current date on the remote */
public Date getRemoteDate( ) throws java.rmi.RemoteException;
/** The name used in the RMI registry service. */
public final static String LOOKUPNAME = "RemoteDate";
}
It's necessary for this file to list all the methods that will be callable from the server by the client.
The lookup name is an arbitrary name that is registered by the server and looked up by the client to establish communications between the two processes.
6.3 RMI Client
Assume for now that the server object is running remotely. To locate it, we use Naming.lookup( ) , passing in the lookup name. This gives us a reference to a proxy object an object that, like the real server object, implements the remote interface but runs in the same Java Virtual Machine as our client application. Here we see the beauty of interfaces: the proxy object implements the interface, so our code can use it just as it would use a local object providing the given service. And the remote object also implements the interface, so the proxy object's remote counterpart can use it exactly as the proxy is used.
Next Example shows the client for the RemoteDate service.
Example DateClient.java
package darwinsys.distdate;
import java.rmi.*;
import java.util.*;
/* A very simple client for the RemoteDate service. */
public class DateClient {
/** The local proxy for the service. */
protected static RemoteDate netConn = null;
public static void main(String[] args) { try {
netConn = (RemoteDate)Naming.lookup(RemoteDate.LOOKUPNAME);
Date today = netConn.getRemoteDate( );
System.out.println(today.toString( )); // XX use a DateFormat...
} catch (Exception e) {
System.err.println("RemoteDate exception: " + e.getMessage());
e.printStackTrace( );
} } }
6.4 RMI SERVER
Basic Steps: RMI Server1. Define (or locate) the remote interface in agreement with the client.
2. Specify the remote interface being implemented.
3. Define the constructor for the remote object.
4. Provide implementations for the methods that can be invoked remotely.
5. Create and install a security manager.
6. Create one or more instances of a remote object.
7. Register at least one of the remote objects with the RMI remote object registry.
This implementation divides the server into the traditional two parts, a main program and an implementation class. It is just as feasible to combine these in a single class. The main program shown in next example simply constructs an instance of the implementation and registers it with the lookup service.
Example DateServer.java package darwinsys.distdate;
import java.rmi.*;
public class DateServer {
public static void main(String[] args) {
// we may want a SecurityManager for downloading of classes:
// System.setSecurityManager(new RMISecurityManager( ));
try {
// Create an instance of the server object RemoteDateImpl im = new RemoteDateImpl( );
System.out.println("DateServer starting...");
// Locate it in the RMI registry.
Naming.rebind(RemoteDate.LOOKUPNAME, im);
System.out.println("DateServer ready.");
} catch (Exception e) { System.err.println(e);
System.exit(1);
} } }
The Naming.bind( ) method creates an association between the lookup name and the instance of the server object. This method will fail if the server already has an instance of the given name, requiring we to call rebind( ) to overwrite it. But since that's exactly where we'll find ourself if the server crashes (or we kill it while debugging) and we restart it, many people just use rebind( ) all the time.
The implementation class must implement the given remote interface.
public class RemoteDateImpl extends UnicastRemoteObject implements RemoteDate
{
/** Construct the object that implements the remote server.
* Called from main, after it has the SecurityManager in place.
*/
public RemoteDateImpl( ) throws RemoteException { super( ); // sets up networking
}/** The remote method that "does all the work". This won't get
* called until the client starts up.
*/
public Date getRemoteDate( ) throws RemoteException { return new Date( );
} }
Using the server
Once compiled the implementation class, we can run rmic (RMI compiler) to build some glue files and install them in the client's CLASSPATH:
$ jikes -d . RemoteDateImpl.java
$ ls darwinsys/distdate
DateApplet$1.class DateClient.class RemoteDate.class DateApplet.class DateServer.class
RemoteDateImpl.class
$ rmic -d . darwinsys.distdate.RemoteDateImpl
$ ls darwinsys/distdate
We must also ensure that TCP/IP networking is running, and then start the RMI registry program.
If we're doing this by hand, just type the command rmiregistry in a separate window, or start or background it on systems that support this.
6.5 Deploying RMI Across a Network
As shown so far, the server and the client must be on the same machine -- some distributed System.
Get the RMI registry to dish out the client stubs on demand.
RMI does not provide true location transparency, which means that we must at some point know the network name of the machine the server is running on. The server machine must be running the RMI registry program as well, though there's no need for the RMI registry to be running on the client side.
Now the RMI registry needs to send the client stubs to the client. The best way to do this is to provide an HTTP URL and ensure that the stub files can be loaded from our web server.
This can be done by passing the HTTP URL into the RMI server's startup by defining it in the system properties:
java -Djava.rmi.server.codebase=http://serverhost/stubsdir/ ServerMain
In this example, serverhostis the TCP/IP network name of the host where the RMI server and registry are running, and stubsdir is some directory relative to the web server from which the stub files can be downloaded.
Be careful to start the RMI registry in its own directory, away from where we are storing (or building!) the RMI stubs. If RMI can find the stubs in its own CLASSPATH, it will assume they are universally available and won't download them!
The only other thing to do is to change the client's view of the RMI lookup name to something like rmi://serverhost/foo_bar_name. And for security reasons, the installation of the RMI Security Manager, which was optional before, is now a requirement.
Exercise:
1. Write a rmi application to provide arithmetic operation(addition, subtraction, multiplication and division) from client program.
2. Write a rmi application for user login module and in this module client program should be applet based.