
Server-side Object Caching Framework
Versions 1.0-2.x
By: Kamran Zafar
Overview
S3C is a Simple Server-Side object Caching framework that allows web developers to cache objects on server-side for fast retrieval. These objects can be of any type e.g. Java beans that are loaded from database. S3C makes it easier to store objects on the application server in a global JNDI context and make them readily available to the application. S3C being available in global context allows more then one application to use and share the same cache and work in their own registered spaces that avoids synchronization issues.
Design

S3C is global to the entire application. When the application is deployed on the server it loads the cache using "CacheLoaderServlet" [Note: The cache can also be deployed and loaded as a separate war file without making it part of the application itself, this way is recommended especially if the cache is to be shared among more then one application. Multiple instances of Caches can also be loaded]. The loader servlet requires a cache configuration file to create and load a cache on the server. Once the cache is loaded it can be used to store objects. But before the application or module of an application can store objects it must registers a Slot (space) in the cache. When the application module registers a Slot then it can start storing/caching object in that Slot. The application can register as many slots it needs in cache or a limit can be specified in a configuration file on the number slots can be created.

S3C framework also provides ways to invalidate the space on server created to store objects. The invalidation message is passed to all the relevant objects that can accordingly decide what processes are to be performed on invalidation. This is done by custom event listener. Invalidation of Cache or Slot is done either at user defined time interval or forcefully by some object. There are two categories of events "xeus.s3c.event.CacheEvent" that is generated when the cache is updated (meaning space is created to store objects or destroyed) and invalidated (meaning when cache itself has been invalidated or outdated). The other event is "xeus.s3c.event.SlotEvent" that is fired when the Slot is invalidated or updated. The invalidation time can be configured before the Cache in the configuration file.

Configuration
Below sample configuration is shown for a cache:
<?xml version='1.0'?>
<!DOCTYPE cache SYSTEM "s3c.dtd">
<cache
name="testCache" slots="5" timeout="60000"> <slot name="testSlot1" timeout="10000"/> <slot name="testSlot2" timeout="10000"/><slot name="testSlot3" timeout="10000"/>
</cache>
This configuration shows that a cache named "testCache" is to be created on the application server with an invalidation time of 60 seconds and the number of slots that can be created in the cache are "5". Slots can also be created at the cache-load-time. Here three slots are registered in the cache with names "testSlot1", "testSlot2" and "testSlot3" with invalidation time of 10 seconds. The application can use these slots to pull and cache data (objects). The "timeout" and "slots" are not required as if they are not present then the cache or slot can never be invalidated and there will be no restriction on the number of slots created in the cache. If the cache is not created because of IO or parsing errors in the configuration file then a "xeus.s3c.exception.CacheException" is thrown.
Loading a Cache on deployment
The cache can be loaded as the application is deployed by loading the "xeus.s3c.loader.CacheLoaderServlet". This process can be configured in "web.xml" file as shown below:
<servlet> <servlet-name>loader
</servlet-name>
<servlet-class>
xeus.s3c.loader.CacheLoaderServlet
</servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/s3c.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>The init-param "config" parameter requires the path to cache configuration file which was shown previously, if the configuration file is not found in the given parameter then it will be looked-up in /WEB-INF/ directory [Note: It is better to always use /WEB-INF/s3c.xml path to avoid errors]. The value of load-on-startup parameter has to be a positive integer that shows the order in which this servlet is to be loaded, the value of 1 means that this is the first servlet that is to be loaded.
Creating a cache
Apart from loading Cache using the "CacheLoaderServlet", any number of instances of cache can be created from inside the application if not loaded on deployment, using the "create" method of "xeus.s3c.CacheManager" class. There are two overloaded version of create method available, one that takes a cache name as parameter and the other that takes timeout and number of slots as parameters along with cache name. If the cache with the given name is already loaded and bound in JNDI then a "xeus.s3c.exception.CacheException" is thrown. Below are shown ways to create a cache.
.
.
Cache cache=CacheManager.create("testCache");
or
Cache cache=CacheManager.create("testCache",120000,10);
Looking-up cache
Whenever the cache is needed then it is to be looked-up by using the lookup method of the "xeus.s3c.CacheManager" class that requires a String cache name as parameter.
.
.
Cache cache=CacheManager.lookup("testCache");
If the cache "testCache" is loaded then a reference of type "xeus.s3c.Cache" will be returned otherwise this method will throw "xeus.s3c.exception.CacheException".
Registering Slot for caching
Once the reference of the Cache object is successfully obtained from the xeus.s3c.CacheManager" class a Slot can be registered in the cache using it's "register" method. There are two register methods overloaded in the Cache interface one that takes the name of the slot as parameter and the other that takes the name and the timeout value.
.
.
Cache cache=CacheManager.lookup("testCache");
Slot slot=cache.register("myBooksSlot");
slot.put("myJavaBook",myBookBean);
The "get" and "put" methods of the Slot object can be used to pull and cache data. If the slot with the name given is already registered in the cache then a"xeus.s3c.exception.SlotNotAvailableException" is thrown.
Listening to cache events (version-1.0)
The cache can be listened for update and invalidation events using "xeus.s3c.event.CacheListener" interface. This interface provides two methods "cacheUpdated" and "cacheInvalidated". When a slot is registered or unregistered in the cache the cache's "updated" event is fired and all the listener objects' "cacheUpdated" method will execute. Same is the case will the cache's "invalidate" event that is fired when the cache is invalidated.
class
ApplicationHandler
implements CacheListener
{
public
void init()
{
Cache cache=CacheManager.lookup("testCache");
cache.addCacheListener(this);
}
public
void cacheUpdated(CacheEvent event)
{
// Do something, may be update "View"
}
public
void cacheInvalidated(CacheEvent event)
{
// Remove application data from cache
}
}
The Slot can also be listened for events using "xeus.s3c.event.SlotListener". Two events "update" and "invalidate" are fired just like the cache events executing the listener objects' "cacheUpdated" and "cacheInvalidated" methods respectively.
class BookLoader
implements SlotListener
{
public
void init()
{
Cache cache=CacheManager.lookup("testCache");
Slot slot=cache.lookup("myBookSlot");
slot.addSlotListener(this);
}
public
void slotUpdated(SlotEvent event)
{
// Do something, may be signal to the
record readers to start reading or update "View"
}
public
void slotInvalidated(SlotEvent event)
{
// Refresh slot..
Slot slot=(Slot) event.getSource();
slot.empty();
//load records.. cache new beans
slot.put("myJavaBook",newBookBean);
slot.put("myCBook",newBookBean);
slot.put("myDatabaseBooks",newBookBeanVector);
}
}
Note: Version two provides better event handling. It allows objects to listen every single change in Cache and Slot objects. Read below for more details.
Forced Invalidation
Besides invalidating cache/slot after a certain user defined time interval, invalidation can also be forced by invoking the "invalidate" methods of Cache and Slot objects. This is the same in both versions.
S3C Version 2.0 Enhancements
Better Track of things
S3C in Version 2.0 provide ways to deeply monitor the slot and cache updates. S3C in version 2.0 provides better event handling.
Cache events
Two new methods are added in "CacheListener"; "slotRegistered" and "slotUnregistered" which are invoked when a slot is registered and unregistered. So now the Listener class must implement these methods. The CacheListener's "slotUpdated" method now is called when some application object "decides" that the cache is "desirably" updated by invoking the Cache's "updated" method. The "CacheEvent" now provides the "getSlotName()" method to see which slot has registered/unregistered.
class
ApplicationHandler
implements CacheListener
{
public
void init()
{
Cache cache=CacheManager.lookup("testCache");
cache.addCacheListener(this);
}
public
void cacheUpdated(CacheEvent event)
{
// Do something, may be update "View"
}
public
void cacheInvalidated(CacheEvent event)
{
// Remove application data from cache
}
public
void slotRegistered(CacheEvent event)
{
// Invoked when a slot is registered
// can be used for logging
}
public
void slotUnregistered(CacheEvent event)
{
// Invoked when a slot is
unregistered
// useful for logging
}
}
Slot events
Slot Listener now provides three new methods "elementAdded", "elementRemoved" and "slotEmptied", which are invoked when a slot is added, removed and emptied respectively. Every slot listener now must implement these methods. The slot listener's "slotUpdated" method is called when some application object "decides" that the slot has been "desirably" updated and calls the "updated" method of the Slot Object. The "SlotEvent" provides "getElementName" method that returns the name of the elements that has been and added in or removed from the Slot.
class BookLoader
implements SlotListener
{
public
void init()
{
Cache cache=CacheManager.lookup("testCache");
Slot slot=cache.lookup("myBookSlot");
slot.addSlotListener(this);
}
public
void slotUpdated(SlotEvent event)
{
// Do something, may be signal to the
record readers to start reading or update "View"
}
public
void slotInvalidated(SlotEvent event)
{
// Refresh slot..
Slot slot=(Slot) event.getSource();
slot.empty();
//load records.. cache new beans
slot.put("myJavaBook",newBookBean);
slot.put("myCBook",newBookBean);
slot.put("myDatabaseBooks",newBookBeanVector);
// Fire update event...
slot.updated();
}
public
void elementAdded(SlotEvent event)
{
// Invoked when an element is added
in the slot
// useful for logging
}
public
void elementRemoved(SlotEvent event)
{
// Invoked when an element is removed
from the slot
// useful for logging
}
public
void slotEmptied(SlotEvent event)
{
// Invoked when a slot is emptied
// useful for logging
}
}
Note: In version 2.1 Adaptor classes are provided for Listeners
Installation
The project can be compiled and build using Ant. When the project is built it creates an "s3c.jar" file that should be included in the application's classpath. Task for project's Java Doc creation also can be found in the ant build file. The "lib" folder provides all the dependency jar files that must be included in the "classpath" with "s3c.jar".
Deployment as a Web Archive (WAR)
With the download bundle comes an "S3C.war" folder. To deploy the cache on the application server simply edit the "s3c.xml" configuration file located in the S3C.war/WEB-INF directory, modify it as required and then simply copy and paste (deploy) the "S3C.war" folder on your application server.
Deployment as JBoss Service (MBean)
The ANT build file in version 2.1 can also be used to create an S3C.sar folder that is deployable as a JBoss service. The new classes in "xeus.s3c.service.jboss" are used for this purpose. The "jboss-service.xml" file must be modified in order for the Cache to run as an MBean and the "configURL" attribute is needed; the value of this attributes is the URL of the cache configuration file 's3c.xml'. [ Note: To build the project put the 'jboss-system.jar' and 'jboss-jmx.jar' files in classpath. These jars are found in the lib folder at JBOSS HOME ]
CVS Access
The latest source code can be checked out through anonymous (pserver) CVS with the following instruction set in Unix based systems. Windows users can use WinCVS to access the code.
cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/s3cache co -P S3C
Note: See the API reference for more info
Email Kamran (author) at: xeus.man@gmail.com
S3C is open source and is distributed under GPL.
DOWNLOAD | LICENSE | AUTHOR'S HOMEPAGE
(S3C) Simple Server-side Object Caching Framework
Copyright (C) 2005 Kamran Zafar