Using RMI with Apache Jserv - Design the Remote Interface (
Page 2 of 4 )
First we must decide what kind of interface the address book will have; what
type of interactions do we want to allow the remote client to have? For basic
functionality, the directory should include the ability to search, get an
entry's details, add an entry, and to retrieve all the entries.
directory/Directory.java:
package directory;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Directory extends Remote {
Entry getEntry(String key) throws RemoteException;
String addEntry(Entry newEntry) throws RemoteException;
Entry [] getEntries() throws RemoteException;
Entry [] search(String query) throws RemoteException;
}
The above Java file defines the remote interface through
which the remote client and server will communicate. The requirements for a
remote interface is that it extend the
java.rmi.Remote class and that
each remote method defined throw the
java.rmi.RemoteException in
addition to whatever application specific exceptions it might throw. One issue
to be mindful of is that the methods' arguements and return values are
transported over RMI, so they must implement the
Serializable
interface.
The Entry class represents the directory
records which are stored & managed by the a class implementing the
Directory interface.
{mospagebreak title=Implement the Remote
Interface}
The server.AddressBook is the
implementation of the Directory interface, extending
UnicastRemoteObject. A UnicastRemoteObject is a convenience
class, facilitating RMI communications. It is not necessary for the server to
have the UnicastRemoteObject superclass, but then you would have to call
serveral UnicastRemoteObject methods yourself to make the service
RMI-enabled.
package server;
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import directory.Directory;
import directory.Entry;
public class AddressBook extends UnicastRemoteObject implements Directory {
public Entry getEntry(String key) throws RemoteException {
// getEntry() method body
}
public String addEntry(Entry e) throws RemoteException {
// addEntry() method body
}
public Entry[] getEntries() throws RemoteException {
// getEntries() method body
}
public Entry[] search(String query) throws RemoteException {
// search() method body
}
public static void main (String args[]) {
// main method body (see below)
}
}
The main() method allows the AddressBook to be run from the
command line. After ensuring a workable SecurityManager is installed,
the rmiregistry is started up. In the examples in Sun's RMI Tutorial, the rmiregistry is started as a
different process by running the "rmiregistry" program found in the
jdk1.x.x/bin directory. Instead, we will automatically create the
rmiregistry in main() method with a call to
LocateRegistry.createRegistry() on port 4000. It should be noted that
the RMI registry could be hosted on a completely different machine too. You
would replace localhost in the name string with the hostname of
the machine running the RMI registry.
public static void main (String args[]) {
AddressBook addressBook = null;
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
System.out.println("Creating RMIRegistry...");
LocateRegistry.createRegistry(4000);
String name = "//localhost:4000/addressBook";
System.out.println("Creating Address Book...");
addressBook = new AddressBook();
Naming.rebind(name, addressBook);
System.out.println("Address Book created ...");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Populating AddressBook...");
addressBook.addEntry(new ServerEntry("Jeff", "jeff@foo.org"));
addressBook.addEntry(new ServerEntry("Leonardo", "leo@foo.org"));
addressBook.addEntry(new ServerEntry("Jose Alexis", "ja@foo.org"));
addressBook.addEntry(new ServerEntry("Walter", "walter@foo.org"));
addressBook.addEntry(new ServerEntry("Chris", "chris@foo.org"));
}
After the
rmiregistry is created, a new
AddressBook is created, and then bound to the
rmiregistry. The
Naming.rebind() registers the AddressBook's Directory service in the
rmiregistry on port 4000 of the localhost, making it available to clients.
Lastly, the addressbook is populated with serveral Entries.
{mospagebreak title=Compile the classes, and create the stub and skeleton
classes}
Compiling the classes is pretty straightforward; just use javac to
compile the classes. From the base directory, do:
$ javac directory/*.java
$ javac server/*.java
on Windows operating systems it will look something like:
> javac directory\*.java
> javac server\*.java
Next, create the stub and skeleton classes
(AddressBook_Skel.java and
AddressBook_Stub.java) using the
rmic tool.
rmic -d . server.AddressBook
The -d flag tells
rmic to where to place the
generated stub and skeleton classes. In this case, the generated classes are
placed relative to the local directory, in the
server package. The
skeleton file is a server-side object which handles forwarding remote method
invocations to the actual server-side implementation. The stub file is deployed
on the client side, serving as a proxy for remote clients to forward method
calls to the server side implementation.