| By Michael Remijan | Article Rating: |
|
| November 5, 2004 12:00 AM EST | Reads: |
26,360 |
Java's implementation of Remote Method Invocation (RMI) is easy to use and powerful. Java makes setting up an RMI server an almost trivial task because the JVM handles complex tasks such as networking and object serialization. Once running, connecting client applications to the RMI server is also a breeze.
There are numerous examples and how-to articles for client-to-server communication (http://java.sun.com/developer/onlineTraining/rmi), but what about the other way? Is it possible for an RMI server to actively communicate with all the clients that are connected to it without the client initiating the conversation? In other words, is distributed notification possible? The purpose of this article is to demonstrate that yes, it is possible. (The source code for this article can be downloaded from www.sys-con.com/jdj/sourcec.cfm.)
RMI applications are driven by the need to have centrally located business logic used by multiple clients at the same time. This presents a number of problems, such as clients not knowing what other clients are doing. A simple example that immediately demonstrates this problem is caching data on the client side for fast reuse. When one client updates information, all the other clients are now working with old data.
The typical - and not the best - solution for this problem is to have each client poll the RMI server for updates on a regular basis. First, constant polling puts unnecessary strain on the RMI server because it's forced to handle additional network traffic. Second, there will be a period of time when the client is working with old data. In the J2EE world, Java Messaging Service (JMS) solves this problem the best. Assuming all data updates are done at a central location, a JMS message can be easily sent to all registered clients when an update occurs. When a client receives the message, the cache can be refreshed.
An alternative solution is to keep plain RMI and follow the event notification model similar to AWT/Swing. In those models, an object implements a simple listener interface and is then added to an appropriate event notification list. When that event occurs, every object in the list becomes notified of the event. The object takes whatever action necessary in response to the event. Such a model obviously is a better solution than polling, and solves the problems that polling has - there is no unnecessary network traffic and clients are notified instantly when a change in the data has occurred.
Applying this model to RMI is not trivial. Consider an RMI-based time server as an example, where client applications register with an RMI server. Every second the RMI server fires an event to inform the clients of the new time. To successfully do this, first define a remote interface named TimeServices.
import java.rmi.*;
public interface TimeServices extends Remote
{
public void addTimeMonitor(TimeMonitor tm)
throws RemoteException;
}
The TimeServices interface declares the methods used for client-to-server communication (see Figure 1).
The Remote interface has one method, addTimeMonitor (TimeMonitor), which is used by RMI client applications to register themselves with the RMI server. This is analogous to the setActionListener() methods in Swing only instead of implementing the ActionListener interface, an object that implements the TimeMonitor interface is needed. Just as the ActionListener interface serves to link an event with the application code that processes the event, the TimeMonitor Interface serves as a way for the RMI Server to talk back to its clients.
import java.rmi.*;
import java.util.Date;
public interface TimeMonitor extends Remote
{
public void setTime(Date d)
throws RemoteException;
}
Because of this, TimeMonitor is a remote interface that allows server-to-client communication (see Figure 2).
Implementing the TimeMonitor interface becomes a challenge, because it's not possible for every client to create its own implementation and use that implementation to register with the RMI server. When the client tries to register with the server by calling the addTimeMonitor() method, the TimeMonitor parameter serializes to a byte stream and is transmitted over the network to the server. The server then needs to know how to deserialize the stream and reconstitute the object. Even though syntactically the TimeMonitor interface is needed to compile, when the server is actually running it needs the implementation of the TimeMonitor interface in the CLASSPATH in order to deserialize the TimeMonitor objects correctly. If the implementation was not in the CLASSPATH, a ClassNotFoundException is thrown when the RMI server attempts to deserialize the stream.
To get around this problem, the client must use an implementation of TimeMonitor that the RMI server provides. Assume this implementation is a class named ServerClock (see Listing 1). Since ServerClock implements the TimeMonitor interface, it's easy to have new instances of this object register itself with the RMI server. The constructor of the ServerClock class can do just this. Once registered, communication can go back and forth between the client and server (see Figure 3).
The client would create an instance of this class by supplying the name and port number of the RMI server.
ServerClock serverClock = new ServerClock(serverName, port);
The ServerClock constructor performs two critical operations. First, it makes this method call:
UnicastRemoteObject.exportObject( this );
According to the J2SE documentation, this method call dynamically "exports the remote object to make it available to receive incoming calls using an anonymous port." Making this method call is the key that allows the server to communicate with all the various clients without requiring stub classes from the client, or knowing the names and ports of client machines.
Second, the constructor contacts the RMI server and registers the object by calling the addTimeMonitor() method:
timeServices.addTimeMonitor( this );
This doesn't result in a ClassNotFound-Exception because the keyword "this" refers to an instance of the ServerClock object that the RMI server provided.
Now the ServerClock class needs to implement the setTime(Date) method of the TimeMonitor class:
/**
* TimeMonitor interface method
*/
public void setTime(Date d)
{
System.out.println("The new time is: " + d);
}
This implementation of setTime(Date d) will technically work, but the RMI client will never know that the RMI server called this method because all the method does is print the Date object to standard out. The RMI client needs to be notified by the ServerClock whenever the setTime(Date d) method is called. A simple solution is for the RMI server to define another, nonremote interface Seconds-Listener:
import java.util.Date;
public interface SecondsListener
{
public void tick(Date d);
}
then add a method to ServerClock that stores implementations of SecondsListener in a vector.
/**
* add listener to list
*/
public void addSecondsListener(Seconds Listener sl) {
synchronized(listeners) {
if (!listeners.contains(sl)) {
listeners.add(sl);
}
listeners.notifyAll();
}
}
Finally, ServerClock's implementation of the setTime(Date d) method is changed to loop over the vector.
/**
* TimeMonitor interface method
*/
public void setTime(Date d)
{
synchronized(listeners) {
for (
Iterator itr=listeners.iterator();
itr.hasNext();
((SecondsListener)itr.next()).tick(d)
) {}
listeners.notifyAll();
}
}
With these additions in place, the client can create as many listener classes as are needed and register the classes with ServerClock:
ServerClock serverClock = new ServerClock(serverName, port); serverClock.addSecondsListener(new ListenerA()); serverClock.addSecondsListener(new ListenerB()); serverClock.addSecondsListener(new ListenerC()); ...
Since the SecondsListener implementations exist on the client, there is no problem with ClassCastExceptions.
Summary
This article successfully shows the event notification model applied to RMI so an RMI server can notify registered clients of events as easily as a JButton notifies its ActionListeners when the button is pushed.
The RMI server is the place where events are generated and fired. A remote interface (TimeServices) allows an RMI server-supplied object (ServerClock) to add itself to an event notification list on the server. Another remote interface (TimeMonitor) allows the server to communicate back with the client when the event occurs. The server-supplied object (ServerClock) allows the client to add an arbitrary number of local objects implementing a nonremote, server-supplied interface (SecondsListener). When the RMI server fires an event (TimeMonitor.setTime(Date)), the server-supplied object (ServerClock) loops over its list of registered listeners and passes the event along.
Published November 5, 2004 Reads 26,360
Copyright © 2004 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Michael Remijan
Michael J. Remijan is a research programmer at the National Center for Supercomputing Applicaitons (NCSA). His chief responsibilities include data miming and access to terabyte-sized astronomy data sets. Michael received a BS in mathematics and computer science from the University of Illinois and is currently working on an MBA in technology management.
![]() |
Fernando Ortiz 11/19/04 02:51:09 PM EST | |||
I guess the link was put there by mistake the link should be http://www.sys-con.com/java/sourcec.cfm |
||||
![]() |
bob roth 11/14/04 09:33:38 PM EST | |||
YOur article point to a url: www.sys-con.com/jdj/sourcec.cfm |
||||
![]() |
Deshpande. 11/13/04 12:34:23 AM EST | |||
It is interesting to know this architecture, i feel this is best suited for intranet applications, considering the reliability of the network. |
||||
![]() |
Raazi Konkader 11/09/04 11:54:14 PM EST | |||
The second solution is something that I tinkered with a few years ago. Of course it was an intranet application and scalability was not an issue as the user base was low. |
||||
![]() |
David 11/09/04 05:17:30 PM EST | |||
RMI over the Internet can have serious issues. Because you do not open/close connections via RMI, there are all sorts of problems when the Internet gets bogged down and connections need to be reset. Also, you may run into various firewall issues when the server attempts to connect back to a remote client and that socket has to be re-established through the firewall -- in which accepting outside connections is generally not allowed. |
||||
- Kindle 2 vs Nook
- Why IBM’s Server Chief Got Busted
- Is Cloud Computing Like Teenage Sex?
- Industry Experts Discuss the State of Cloud Computing
- Performance Tuning Essentials for Java
- Confessions of a Ulitzer Addict
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- It's the Java vs. C++ Shootout Revisited!
- Cloud Computing Can Revitalize Your Career as Software Developer
- IBM Could "Reinvent" Java: Mills
- Oracle & Cloud Computing: Exclusive Q&A with SVP Richard Sarwal
- A Brief History of Cloud Computing
- Kindle 2 vs Nook
- Cloud CEOs, CTOs & SVPs to Speak at 4th International Cloud Computing Expo
- Why IBM’s Server Chief Got Busted
- Is Cloud Computing Like Teenage Sex?
- Industry Experts Discuss the State of Cloud Computing
- Performance Tuning Essentials for Java
- The Difference Between Web Hosting and Cloud Computing
- Cloud Computing Expo: Exclusive Q&A with Yahoo! SVP Cloud Computing
- Ajax in RichFaces 3.3, JSF 2 and RichFaces 4
- Confessions of a Ulitzer Addict
- My Thoughts on Ulitzer
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- A Cup of AJAX? Nay, Just Regular Java Please
- Java Developer's Journal Exclusive: 2006 "JDJ Editors' Choice" Awards
- The i-Technology Right Stuff
- JavaServer Faces (JSF) vs Struts
- Rich Internet Applications with Adobe Flex 2 and Java
- Java vs C++ "Shootout" Revisited
- Bean-Managed Persistence Using a Proxy List
- Reporting Made Easy with JasperReports and Hibernate
- Creating a Pet Store Application with JavaServer Faces, Spring, and Hibernate
- What's New in Eclipse?
- Why Do 'Cool Kids' Choose Ruby or PHP to Build Websites Instead of Java?
- i-Technology Predictions for 2007: Where's It All Headed?









































