Server Side - Java - Using Rmi With Apache Jserv

Download as pdf or txt
Download as pdf or txt
You are on page 1of 16

Using RMI with Apache Jserv

By Richard Yumul

All materials Copyright © 1997−2002 Developer Shed, Inc. except where otherwise noted.
Using RMI with Apache Jserv

Table of Contents
Introduction.........................................................................................................................................................1

Design the Remote Interface..............................................................................................................................3

Implement the Remote Interface.......................................................................................................................4

Compile the classes, and create the stub and skeleton classes........................................................................7

Create the client program (the servlet).............................................................................................................8


Make the JAR files.................................................................................................................................10
Deploy the classes in Jserv....................................................................................................................11

Conclusion.........................................................................................................................................................14
Resources...............................................................................................................................................14

i
Introduction
One of the greatest advantages which Jserv brings to Apache is ability to leverage the large number of API's
available to Java. Remote Method Invocation (RMI) delivers several significant benefits to the servlet
solution. The primary benefit of using RMI with servlets is that it significantly expands the variety of
datasources which Apache can serve to the browser. Furthermore, RMI's simplifies code on the client side of
the RMI connection (the servlet), and also allows for load distribution.

For example, if you wanted a servlet to access a database through JDBC, you would start off with importing
the java.sql package into your servlet. Then your servlet would have to manage handling the database
connection, preparing and executing SQL statements, as well as managing the result sets. This adds a lot of
complexity to your servlet, as not only does it have to handle logic &return appropriate responses to the
browser, it is also bogged down managing communications with the database.

Servlet <== JDBC ==> Database

With RMI, an abstraction layer is added between the data source and the servlet. This layer, the RMI Service
(or server tier), provides an simplified interface to the client, handling all of the internals of communicating
with the database.

Servlet <== Remote Interface ==> RMI Service


<== JDBC ==> Database

z So, instead of having to manage the database communications in your servlet, RMI hides all the that from
your servlet behind its remote interface.

With RMI, the server tier can be anything, as long as it implements the defined remote interface. The service
could even be hosted on a different machine with a different operating system. The client will not care if the
server tier stores its data in a database, LDAP server, or even text files. Your Linux Apache−Jserv box could
be pulling data from an application server on a Solaris box.

Example

Using RMI with Apache Jserv is fairly straight−forward, and the procedure in this example pretty much
follows the RMI examples which can be found in the JDK documentation or Sun's tutorial (links in the
Resources section ). The steps include:

1. Design the remote interface


2. Implement the remote interface
3. Compile the classes, create the stub and skeleton classes
4. Create the client program (in this case, the servlet)
5. Deploy

Introduction 1
Using RMI with Apache Jserv
In the following example, we will create a simple email address book. The server will store it's data in a
Hashtable. Of course, the data in the server will disappear when the server is stopped, but that's okay for
this example's purposes. For a more robust server, the address book data could be stored in a database, LDAP
server, or any other type of data storage. The servlet (client) will use the address book service through RMI.

There are three packages in our example. The first one, is the directory.* package. It holds the remote
interface class, as well as the Entry class, a data structure representing an directory record. The server
package will contain the implementation of the remote interface. The client package contains the servlet
which talks to the server implementation via RMI.

Introduction 2
Design the Remote Interface
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.

Design the Remote Interfa... 3


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)
}
}

Implement the Remote Inte... 4


Using RMI with Apache Jserv
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", "[email protected]"));
addressBook.addEntry(new ServerEntry("Leonardo",
"[email protected]"));
addressBook.addEntry(new ServerEntry("Jose Alexis",
"[email protected]"));
addressBook.addEntry(new ServerEntry("Walter",
"[email protected]"));
addressBook.addEntry(new ServerEntry("Chris",
"[email protected]"));
}

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

Implement the Remote Inte... 5


Using RMI with Apache Jserv
on port 4000 of the localhost, making it available to clients. Lastly, the addressbook is populated with serveral
Entries.

Implement the Remote Inte... 6


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.

Compile the classes, and ... 7


Create the client program (the servlet)
Enabling the servlet (Booklet.java) to talk to the remote Directory service is a fairly straightforward
procedure. Just like any other RMI client, the servlet instantiates the remote object with a call to
Naming.lookup(). After the remote object is instantiated, you can work with the object as if it were local.

The init() and doGet() methods are the particularly interesting methods in the Booklet servlet.

public class Booklet extends HttpServlet {

private Directory dir;


private String url;

public void init(ServletConfig config) throws ServletException


{
super.init(config);

if (System.getSecurityManager() == null ) {
System.setSecurityManager(new RMISecurityManager());

String rmiRegistryHost = getInitParameter("rmiRegistryHost");

if (rmiRegistryHost == null) {
rmiRegistryHost = "localhost";
}

try {
String name = "//" + rmiRegistryHost + ":4000/addressBook";
this.dir = (Directory) Naming.lookup(name);
} catch (Exception e) {
e.printStackTrace();
}
}

public void doGet (HttpServletRequest req, HttpServletResponse


res)
throws IOException, ServletException {
res.setContentType("text/html");
PrintWriter out = res.getWriter();

this.url = req.getRequestURI();

String cmd = req.getParameter("cmd");

printHeader(out);

Create the client program... 8


Using RMI with Apache Jserv
printForm(out);

try {
if (cmd.equals("search")) {
out.println("<h4>Search Results:</h4>");
printResults(dir.search(req.getParameter("query")), out);
} else if (cmd.equals("add")) {
out.println("<h4>New Entry:</h4>");
printEntry(
dir.getEntry(
dir.addEntry(
new ClientEntry( req.getParameter("name"),
req.getParameter("email")
)
)),
out);
} else if (cmd.equals("get")) {
out.println("<h4>Directory Entry:</h4>");
printEntry(dir.getEntry(req.getParameter("key")), out);
} else if (cmd.equals("everybody")) {
out.println("<h4>Complete Directory Listing:</h4>");
printResults(dir.getEntries(), out);
}
} catch (RemoteException e) {
out.print("<h3>Error with the RMI Transport</h3>");
} catch (NullPointerException e) {
out.println("Search for an entry, create an entry, " +
"or get an entry using the forms on the left.");
e.printStackTrace();
}

printFooter(out);
}

// rest of servlet methods....


}

Upon initialization, the servlet first checks the SecurityManager and sets it if needed. Next, the servlet
checks for the initialization parameter named "rmiRegistryHost", the name of the computer hosting the RMI
registry to which the Directory service is bound. To specify the rmiRegistryHost, in your servlet
zone's properties file, insert this line:

servlet.client.Booklet.initArgs=rmiRegistryHost=<machineName>

If this arguement is not defined, the getInitParameter() method will return null and the
rmiRegistryHost will be set to the localhost. Then the init() method obtains the Directory service

Create the client program... 9


Using RMI with Apache Jserv
with Naming.lookup(), and stores it in a private variable, keeping it around for reuse. If the remote
service was obtained inside a service method, like doGet(), the servlet would have to obtain the remote
object with every request, an expensive procedure where repeating it should be minimized. Instead, one
instance of the remote directory service will be reused for the lifetime of the servlet.

The doGet() method, then services the incoming requests to the servlet. It examines the parameters passed
to it from the HTML form and then calls the appropriate methods on the remote Directory service.

Nothing particularly special needs to be done in compiling the client classes; just use the basic java compiler,
javac.

$ javac client/*.java

Windows:

> javac client\*.java

Make the JAR files


Now we're going to bundle our classes into JAR files. While not an absolute requirement, this eases the
deployment step as well as distribution. At the command prompt, type:

$ jar −cvf client.jar client/*.class directory/*.class


server/AddressBook_Stub.class

on Windows operating systems the slashes change to backslashes:

> jar −cvf client.jar client\*.class directory\*.class


server\AddressBook_Stub.class

The "c" tag tells the jar tool to create a new file. The "v" tag turns on verbose output, so you can see exactly
what the jar tool is doing. The "f" tag tells the jar tool that you will specify the name of the jar file to be
created, which is the argument following the "f" tag, client.jar. The next arguments specify which files
should go into the jar file.

On the client side, the only the stub class is absolutely necessary for RMI communication to work.

Create the server jar file:

Create the client program... 10


Using RMI with Apache Jserv
$ jar −cvf server.jar server/*.class directory/*.class

Windows:

> jar −cvf server.jar server\*.class directory\*.class

On the server side, both stub and skeleton classes generated by rmic are necessary.

Deploy the classes in Jserv


So far, the steps in this article have followed the procedures described in Sun's RMI tutorial or the Javadoc.
The only really Jserv specific part is the deployment. Installation of the client servlet is fairly straight forward:

• Copy the client.jar file on to your webserver.


• Add the jar file to Jserv's global classpath. This is done in the jserv.properties file. Add the
line:

wrapper.classpath=/path/to/client.jar

Of course, this is assuming you already have a servlet zone set up. If the
RMI registry is going to be running on a different computer, then
specify the rmiRegistryHost parameter for the servlet as described
above. (If you need help with setting up Apache Jserv, check out Ari
Halberstadt's Using Apache Jserv 1.0,
href="http://www.servletcentral.com/1999−01/jserv.dchtml">http://www.servletcentral.com/1999−01/jserv.dchtml.)

Now restart your Apache Jserv server to ensure that the client.jar
file is accessible and the configuration changes take effect. Typically, an
"apachectl restart" will do it.

Run it!

Now that the client has been deployed, the all that's left to do is to run
the demo. First fire up the server (making sure that the server.jar file is

Create the client program... 11


Using RMI with Apache Jserv
in your classpath...):

java −classpath=$CLASSPATH:/path/to/server.jar \
−Djava.security.policy=java.policy server.AddressBook

Windows:

java −classpath=%CLASSPATH%;\path\to\server.jar
−Djava.security.policy=java.policy server.AddressBook

The server should start, printing status messages to the console.

$ java server.AddressBook
Creating RMIRegistry...
Creating Address Book...
Address Book created ...
Populating AddressBook...
Added entry: Jeff
Added entry: Leonardo
Added entry: Jose Alexis
Added entry: Walter
Added entry: Chris

The −Djava.security.policy=java.policy parameter tells the Java virtual machine to use the
security rules specified in the java.policy file. The file tells the JVM to accept all socket connections on ports
above 1024. This parameter is necessary otherwise other machines won't be able to connect to the rmiregistry.

In a web browser, go to the url which maps to the client.Booklet servlet. For a typical setup, this might
be http://yourhost/servlets/client.Booklet. If you want to abbreviate the URL &not refer
to the servlet by it's package, in your zone.properties file, you could add:

servlet.booklet.code=client.Booklet

This creates an alias for the client.Booklet servlet; it's nick name is "booklet". Now you can access the
Booklet servlet with a URL something like, http://yourhost/servlets/booklet, instead.

The servlet will return a form to your browser which will allow you to interact (search, add entries, select an
entry, get all entries) with the AddressBook through the HTML form.

As you interact with the AddressBook via the servlet, status messages on what the AddressBook is doing
should appear in the console in which it was started.

Create the client program... 12


Using RMI with Apache Jserv

...
All entries retrieved...
Added entry: John
Retrieved entry: John
Queried on:Leo

Create the client program... 13


Conclusion
As you can see, RMI allowed us to host the Directory service on a machine separate from the web server.
Not only does this allow us to load balance applications, but it also allows your Apache Jserv box to connect
to data sources hosted on different machines with different OS's. For example, in a two tier approach, a
WinNT or Solaris server could host the the database or application server, and your Linux Apache−Jserv
machine would then access the data sources via RMI.

The code on the client side is fairly straightforward. The servlet only knows about the Directory interface,
and all the code dealing with the data storage &retrieval is hidden behind that interface. The RMI service
implementation, server.AddressBook is a simple example, using a HashMap to store the data. A more
robust Directory implementation data would store its data in a database or LDAP server. For the servlet
(RMI client), it doesn't matter where the data is coming from; it's happy as long as the service implementing
the directory.Directory interface is available from the RMI registry.

Resources
• Apache Jserv
• Sun's RMI Tutorial
• RMI Documentation distributed with Java 2 SDK

Conclusion 14

You might also like