jZonic-Cache


1. Caching

Caching is an oft overlooked element of an application. It can speed up applications dramatically.

This library consists of two different types of caches. The first part are simple type of caches like a static cache or a last recent updated cache. The other part is the TreeCache which makes managing dependencies between objects simple.

2. The Cache interface

The interface for all caches is very straight forward. Here are all methods:

public void put(Object identifier,Object value);

Stores an object with the given identifier in the cache

public Object get(Object identifier);

Returns the object with the given identifier from the cache if it is available

public int getSize();         

Returns the current size (number of stored objects)

public int getCapacity();

Returns the total capacity (maximum number of objects)

public void delete(Object identifier);

Removes the object with the given identifier

public void clear();

Deletes all objects

public String getDomainName();

Returns the domain name for this cache

public List getAllElements();    

Returns all objects

public boolean contains(Object identifier);    

Returns true if an object with this identifier is in the cache

public Set keySet();

Returns all identifiers as Set

3. The CacheManager

The CacheManager takes care of managing all caches. It keeps a map of all caches referenced by their unique domain name. This manager is implemented as a Singleton so that all classes in the same JVM can have access to a cache. The cache will be instantiated once and then is stored internally by the CacheManager. In order to get a cache call the getCache method. There are three different getCache methods available:

getCache(String domainName,int type)

This returns a cache for the given type with the specified domain name. The capacity is set to 2000 objects and the Time-to-Live ("ttl") is set to -1. This means that the objects in the cache will not expire.

getCache(String domainName,int type,int capacity)

Like the above but defines the capacity.

getCache(String domainName,int type,int capacity,long ttl)

Sets all values. LRU = 1; TTL = 2; STATIC = 3; FILE_CONTENT = 4; TRANSFORMER = 6;

3.1. The list of supported types

The jZonic-cache supports the following types:

Table 1. 

LRU (Least-Recently-Used) 1
TTL (Time-to-Live) 2
STATIC 3
FILE_CONTENT 4
TRANSFORMER 6

The number five was ignored for technical reasons. The different types are explain in a later chapter.

4. The different types of caches

This chapter explains the different types that the jZonic-cache offers.

4.1. Static cache

The static cache will store the objects until a the maximum number of objects is reached. This maximum is defined by the capacity. The default value is 2000 objects.

4.2. LRU

The LRU cache will store objects in the cache until the maximum number of objects is reached. Every new object is moved to the top of the internal list. Each time when an object is requested it is moved to the top. If the maximum number of objects is reached, the new object will be stored at the first place in the list and the last one is removed.

4.3. TTL

This is a timer based cache. Every object has a certain lifetime and will be removed automatically if the object expires. There is also a maximum number of objects defined.

4.4. File content cache

This cache will store the text content of files. It extends the LRU cache. The full qualified filename must be used as qualifier. If the file has changed then the cache will reload it automatically the next time the entry will be accessed.

4.5. Transformer cache

This cache is meant for storing the XSL transformer. This is a helpful cache when it comes to XML/XSL processing. Using a cached transformer will speed up the step of transforming dramatically.

5. CacheHandler

The CacheHandler can be used to load and store the content of a cache.

5.1. SerializeCacheHandler

This handler will serialize the cache to a file and read it back. All objects in the cache must be serializable otherwise the content cannot be stored.

Parameter:

filename: the name of the file that the cache will be stored

5.2. PeriodSerializeCacheHandler

This handler is the same as the one above except that it will store the content periodically to the file. You do not have to call "storeCache" since this is done automatically.

Parameter:

filename: the name of the file that the cache will be stored

period (optional): the interval whenever the cache will be stored in seconds. The default value is 30 minutes.

6. CacheListener

All types of caches supports a listener that notifies all registered listeners if an entry in the cache has been updated or deleted.

In order to register as a listener your class has to implement the CacheListener interface. Here is an example:

import org.jzonic.core.cache.events.*;

public class MyListenerTest implements CacheListener {
    
    public void cacheCleared() {    
    }
    
    public void cacheUpdated(CacheEvent ce) {        
    }
}

6.1. Example

This is a simple example that will demonstrate the listener:

import org.jzonic.core.cache.events.*;
import org.jzonic.core.cache.*;

public class ListenerExample implements CacheListener {
        
    public ListenerExample() {        
    }
    
    public void cacheCleared() {
        System.out.println("the cache was cleared");
    }
    
    public void cacheUpdated(CacheEvent ce) {        
        if ( ce.getType() == CacheEvent.ENTRY_DELETED ) {
            System.out.println("the entry:"+ce.getIdentifier()+" has been deleted");
        }
        if ( ce.getType() == CacheEvent.ENTRY_UPDATED ) {
            System.out.println("the entry:"+ce.getIdentifier()+" has been updated");
        }
    }
    
    public static void main(String[] args) {
        Cache myCache = CacheManager.getCache("MyCache",CacheManager.STATIC);
        myCache.addCacheListener(new ListenerExample());
        myCache.put("Hello","World");
        myCache.delete("Hello");
        myCache.put("And","More to come");
        myCache.clear();
    }        
}

This will write out:

the entry:Hello has been updated
the entry:Hello has been deleted
the entry:And has been updated
the cache was cleared

7. Configuring caches with the cache.xml

In order to prepare certain caches you can use the cache.xml to define them. Make sure that this file is in the classpath of your application.

7.1. The XML structure

The jZonic-Cache does not support the use of a property file to configure certain caches. An XML file is easier to understand and more intuitive to use than a property file. The XML structure is fairly simple:

<?xml version="1.0"?>
<cache-settings>
  <cache name="{name of the cache}">
    <type>{static|lru|ttl|filecontent|transformer}</type>
    <capacity>{maximum size}</capacity>  
    <ttl>{seconds to live}</ttl>
    <handler class="{full qualified name of the handler}">
      <parameter name="{parameter name}" value="{parameter value}"/>
    </handler>  
  </cache>
</cache-settings>  

Inside the "cache-settings" tags you can define as many caches as you need. The "cache" tag requires the name attribute which is the domain name of the cache. The "type" tag defines which type of cache you want and the capacity the maximum number of elements. TTL tag defines the time to live in seconds if the cache supports this.

The "handler" tag is optional. It requires the "class" attribute which must be the full qualified name of the handler and additional sub tags as parameters which will be send to the handler.

7.2. Examples

This is a simple example that will define one static cache called "MyCache". This cache has a capacity of 200 objects that can be stored.

<?xml version="1.0"?>
<cache-settings>
  <cache name="MyCache">
    <type>static</type>
    <capacity>200</capacity>    
  </cache>
</cache-settings>  

The second example will prepare two caches. One static cache called "MyStatic" with a handler and the second one is a TTL cache where every object will expire after 30 minutes:

<?xml version="1.0"?>
<cache-settings>
  <cache name="MyStatic">
    <type>static</type>
    <capacity>1500</capacity>
    <handler class="org.jzonic.core.cache.handler.PeriodSerializeCacheHandler">
      <parameter name="file" value="/tmp/mydir/myfile"/>
      <parameter name="period" value="60"/>
    </handler>    
  </cache>
  
  <cache name="MyTTL">
    <type>TTL</type>
    <capacity>1000</capacity>
    <ttl>1800</ttl>            
  </cache>
</cache-settings>    

8. The TreeCache

So far all cache types used a linear approach for storing the objects. Every object must be associated with an unique key. Sometimes it is helpful to overcome this shortcoming and build a tree of cache objects. This lets you easily manage dependencies between objects. For example you can store the user information in the cache and all his related objects as children. So when you remove the user from the cache all of his objects will be deleted as well.

The TreeCache uses node names that are build like "root/groupa/groupb". Every node has one parent and can have multiple children. When you insert an object into the cache the node will be created automatically. The cache will assume that the parent name is the same without the last part. If this parent does not exist it will be created until the node name is a root element.

8.1. The methods

The TreeCache does not implement the cache interface since the method signatures are different to the regular cache. You can create nodes in the tree and add objects to this node. The nodes are created automatically when you add an object to a node. In order to get an object from the cache you need to specify the path to the node and the key for the object as child of the node. Therefore here is a list of methods that the TreeCache supports

public static TreeCache getInstance(String domainName)

This method returns a TreeCache for the given domain name. If the cache does not exist so far it will be created.

public void clear()

This method will remove all elements from the cache.

public void delete(String identifier)

This method deletes a node and all of its children from the tree.

public void delete(String identifier,String name)

This method deletes an object with the given name from a node with the specific identifier

public Object get(String identifier,String nodeName)

The method returns an object from the cache. The cache will search for a node with the given name "identifier" and the key "nodeName"

public boolean contains(String identifier)

Use this method to determine if there is a node with the given name

public int getSize() 

This returns the current size

public String getDomainName()

Returns the domain name of the cache

public void put(String nodeName,String key,Object value)

Puts an object into the cache at the given node name for the given key. If the parent node does not exist it will be created.

8.2. Examples

Now we will look at some simple examples that should help you getting started.

import org.jzonic.core.cache.*;

public class TreeCacheDemo {

  public static void main(String[] args) {
    // get an instance of our cache 
    TreeCache tc = TreeCache.getInstance("Test");
    // insert a few items
    tc.put("root","item1","Hello");
    tc.put("root","item2","World");
    tc.put("root/groupa/subgroupa","More","Stuff");
    // we have 3 nodes inside
    // root, groupa and subgroupa
    System.out.println("We have "+tc.getSize()+" nodes");
    String value = (String)tc.get("root/groupa/subgroupa","More");
    // this will write out Stuff
    System.out.println("Value is:"+value);
  }
}

Next is an example where we will delete an object

import org.jzonic.core.cache.*;

public class TreeCacheDemo2 {

  public static void main(String[] args) {
    // get an instance of our cache 
    TreeCache tc = TreeCache.getInstance("Test");
    // insert a few items
    tc.put("root","item1","Hello");
    tc.put("root/groupa/subgroupa","More","Stuff");
    // now we delete root/groupa
    tc.delete("root/groupa");
    // and the root/groupa/subgroupa is also gone
    String value = (String)tc.get("root/groupa/subgroupa","More");
    // this will write out null
    System.out.println("Value is:"+value);
  }
}

9. Requirements

The jZonic-cache uses jLo as its logging framework. This library is in the lib directory. When you want to use the cache make sure you have the jlo.jar in your classpath.

The logging framework will search for the log configuration which is stored in a file called jlo_logging.xml. This file is also included in the distribution. You have to make sure that the file is also in the classpath. Otherwise the logger will write everything to the console.

For more informations about jLo please refer to the website http://jlo.jzonic.org.

10. Changelog

The is a list of changes

10.1. Version 1.1

- javadoc improved

- CacheEvent and CacheListener added

- TreeCacheListener and TreeCacheEvent added

- CacheHandler interface and SerializeCacheHandler, PeriodSerializeCacheHandler added

- cache configuration added (simple XML configuration) - several bug fixes in the TTL cache