The CORBA Evictor Pattern in Java
When a CORBA server allows its clients to create and destroy objects one of the recommended ways to handle the object lifetime issues is using the Evictor Pattern. In The Evictor Pattern we solved the problem for C++ servers, here we do the same for Java servers.
The problem
Due to the way that CORBA deals with object lifetime issues you may find it necessary to have the server control the lifetime of objects created on the server by the client. The kind of objects we’re talking about here are the objects that get created for a client when the client calls a method on another object on the server. For example a client may wish to access a collection of objects on a server and to do this may call a method that returns an iterator object. The iterator object has a lifetime that is controlled by the client, the client creates it by requesting it from the server, uses it and eventually destroys it with a call to destroy()
. Unfortunately servants on the server can be leaked if the client does not call destroy()
and because of this it’s best to let the server take control. See the C++ CORBA section for more details of the problems that can occur if you dont let the server manage the lifetime of these objects in some way.
You may be surprised to hear that you have these kind of object lifetime problems with Java. After all, as a Java programmer you’re used to objects being garbage collected when they’re no longer needed - why dont CORBA servants get cleaned up automatically for you? The problem is that the server needs to hold on to a reference to the servant object until the client doesnt want the object any more. If the client behaves itself then there’s no problem, once the client finishes with the object it can tell the server that it no longer requires it and the server can release its last reference and the language run-time can garbage collect the servant object when it wants to. If the client terminates unexpectedly or acts maliciously the the server has no way to manage the references that it is holding on behalf of the clients. One solution to this problem is the evictor pattern.
The Evictor Pattern
For an excellent description of the concept behind the evictor pattern see Advanced CORBA Programming with C++ (APC). In a nutshell, the server decides how long your object can live, when the server decides your time is up it simply destroys your object for you and your next call fails… It doesn’t matter if you forget to release your objects when you’re done, they’ll get cleaned up eventually. It doesn’t matter if you terminate without letting the server know and, well, it doesn’t matter if you have to write heaps of client code to handle exceptional cases of object disappearance…
You’re out…
The simplest evictor works along these lines. The server has finite resources, if those resources are about to be exceeded then the server should garbage collect existing objects that haven’t been used for a while to make way for new objects. The easiest implementation is probably something that uses a least recently used algorithm for eviction of “inactive” servants and is implemented in terms of a ServantLocator
. See the C++ CORBA section for details of the server that this example is based on and to compare the Java implementation with the equivalent C++ implementation.
An evicting ServantLocator
A servant locator is called by the POA that it’s associated with to dispatch method calls to the appropriate servant. By associating a servant locator with a POA we can place code that we’ve written directly in the call sequence for every method dispatch call to any servant that uses that POA. We are now responsible for mapping the CORBA Object ID to the servant that is providing the implementation for that object. Since we manage the mapping we also manage the lifetime of the servants.
Every time we create a servant that is to be managed by our servant locator we must notify the servant locator of the new object so that the object can be added to the servant locator’s mapping table. When the servant locator adds the object to the mapping table it must also generate an Object ID and from the Object ID we can create an object reference that refers to our servant so that we can hand it out to our clients.
When we wish to destroy a servant that is managed by our servant locator the object simply requests that the servant locator remove it from its mapping table. When the servant locator does this there are no more outstanding references to the servant and the run-time can garbage collect the servant.
The evictor pattern comes into play when the servant locator’s Object ID to servant mapping table is full. At this time the servant locator must make space in its mapping table for new servants by removing existing servants. Our servant locator uses a timeout algorithm for deciding which servants to evict.
The actual management of the Object ID to servant mapping is performed by the EvictorQueue
class. This class maintains a fixed size array for servants and the index into the array is used as part of the Object ID for that servant. The actual array holds instances of the EvictableServant
class which contains the servant reference and timestamps that are used for eviction and object identification purposes. Each time that a servant is accessed its last used timestamp is updated and it is moved to the tail of a list that is maintained in least recently used order. When the array of servants is full the least recently used list is scanned for an object that has timedout, all objects that have timed out are evicted from the array and are available for garbage collection by the run-time. If no servants have timedout then an exception is thrown.
Comparing the Java and C++ implementations
The Java implementation is more intrusive than the C++ implementation due to the fact that the Java servant implementation must derive from the appropriate POA class and cannot also derive from a mix-in base class that provides the common servant locator code. We could use a Tie implementation but that is likely to be as complex.
Download
The following source was built using Ant and tested with JacORB 3.21 - the open source Corba Java ORB.
Revision history
- 23rd July 2001 - Initial revision at www.jetbyte.com.
- 23rd August 2005 - reprinted at www.lenholgate.com.