JBoss.orgCommunity Documentation

Chapter 2. User API

2.1. API Classes
2.2. Instantiating and Starting the Cache
2.3. Caching and Retrieving Data
2.4. The Fqn Class
2.5. Stopping and Destroying the Cache
2.6. Cache Modes
2.7. Adding a CacheListener
2.8. Using Cache Loaders
2.9. Using Eviction Policies

The Cache interface is the primary mechanism for interacting with JBoss Cache. It is constructed and optionally started using the CacheFactory . The CacheFactory allows you to create a Cache either from a Configuration object or an XML file. Once you have a reference to a Cache , you can use it to look up Node objects in the tree structure, and store data in the tree.

Reviewing the javadoc for the above interfaces is the best way to learn the API. Below we cover some of the main points.

An instance of the Cache interface can only be created via a CacheFactory . (This is unlike JBoss Cache 1.x, where an instance of the old TreeCache class could be directly instantiated.)

CacheFactory provides a number of overloaded methods for creating a Cache , but they all do the same thing:

An example of the simplest mechanism for creating and starting a cache, using the default configuration values:



   CacheFactory factory = new DefaultCacheFactory();
   Cache cache = factory.createCache();
      

Here we tell the CacheFactory to find and parse a configuration file on the classpath:



   CacheFactory factory = new DefaultCacheFactory();
   Cache cache = factory.createCache("cache-configuration.xml");
      

Here we configure the cache from a file, but want to programatically change a configuration element. So, we tell the factory not to start the cache, and instead do it ourselves:



   CacheFactory factory = new DefaultCacheFactory();
   Cache cache = factory.createCache("cache-configuration.xml", false);
   Configuration config = cache.getConfiguration();
   config.setClusterName(this.getClusterName());
   // Have to create and start cache before using it
   cache.create();
   cache.start();
      

Next, let's use the Cache API to access a Node in the cache and then do some simple reads and writes to that node.



   // Let's get ahold of the root node.
   Node rootNode = cache.getRoot();
   // Remember, JBoss Cache stores data in a tree structure.
   // All nodes in the tree structure are identified by Fqn objects.
   Fqn peterGriffinFqn = Fqn.fromString("/griffin/peter");
   // Create a new Node
   Node peterGriffin = rootNode.addChild(peterGriffinFqn);
   // let's store some data in the node
   peterGriffin.put("isCartoonCharacter", Boolean.TRUE);
   peterGriffin.put("favouriteDrink", new Beer());
   // some tests (just assume this code is in a JUnit test case)
   assertTrue(peterGriffin.get("isCartoonCharacter"));
   assertEquals(peterGriffinFqn, peterGriffin.getFqn());
   assertTrue(rootNode.hasChild(peterGriffinFqn));
   Set keys = new HashSet();
   keys.add("isCartoonCharacter");
   keys.add("favouriteDrink");
   assertEquals(keys, peterGriffin.getKeys());
   // let's remove some data from the node
   peterGriffin.remove("favouriteDrink");
   assertNull(peterGriffin.get("favouriteDrink");
   // let's remove the node altogether
   rootNode.removeChild(peterGriffinFqn);
   assertFalse(rootNode.hasChild(peterGriffinFqn));
      

The Cache interface also exposes put/get/remove operations that take an Fqn as an argument:



   Fqn peterGriffinFqn = Fqn.fromString("/griffin/peter");
   cache.put(peterGriffinFqn, "isCartoonCharacter", Boolean.TRUE);
   cache.put(peterGriffinFqn, "favouriteDrink", new Beer());
   assertTrue(peterGriffin.get(peterGriffinFqn, "isCartoonCharacter"));
   assertTrue(cache.getRootNode().hasChild(peterGriffinFqn));
   cache.remove(peterGriffinFqn, "favouriteDrink");
   assertNull(cache.get(peterGriffinFqn, "favouriteDrink");
   cache.removeNode(peterGriffinFqn);
   assertFalse(cache.getRootNode().hasChild(peterGriffinFqn));
      

The previous section used the Fqn class in its examples; now let's learn a bit more about that class.

A Fully Qualified Name (Fqn) encapsulates a list of names which represent a path to a particular location in the cache's tree structure. The elements in the list are typically String s but can be any Object or a mix of different types.

This path can be absolute (i.e., relative to the root node), or relative to any node in the cache. Reading the documentation on each API call that makes use of Fqn will tell you whether the API expects a relative or absolute Fqn .

The Fqn class provides are variety of constructors; see the javadoc for all the possibilities. The following illustrates the most commonly used approaches to creating an Fqn:



   // Create an Fqn pointing to node 'Joe' under parent node 'Smith'
   // under the 'people' section of the tree
        
   // Parse it from a String
   Fqn<String> abc = Fqn.fromString("/people/Smith/Joe/");
        
   // Build it directly. Marginally more efficient to construct than parsing
   String[] strings = new String[] { "people", "Smith", "Joe" };
   Fqn<String> abc = new Fqn<String>(strings);
        
   // Here we want to use types other than String
   Object[] objs = new Object[]{ "accounts", "NY", new Integer(12345) };
   Fqn<Object> acctFqn = new Fqn<Object>(objs);
     

Note that

Fqn<String> f = new Fqn<String>("/a/b/c");

is not the same as

Fqn<String> f = Fqn.fromString("/a/b/c");

The former will result in an Fqn with a single element, called "/a/b/c" which hangs directly under the cache root. The latter will result in a 3 element Fqn, where "c" idicates a child of "b", which is a child of "a", and "a" hangs off the cache root. Another way to look at it is that the "/" separarator is only parsed when it forms part of a String passed in to Fqn.fromString() and not otherwise.

The JBoss Cache API in the 1.x releases included many overloaded convenience methods that took a string in the /a/b/c format in place of an Fqn . In the interests of API simplicity, no such convenience methods are available in the JBC 2.x API.

It is good practice to stop and destroy your cache when you are done using it, particularly if it is a clustered cache and has thus used a JGroups channel. Stopping and destroying a cache ensures resources like the JGroups channel are properly cleaned up.



   cache.stop();
   cache.destroy();
      

Not also that a cache that has had stop() invoked on it can be started again with a new call to start() . Similarly, a cache that has had destroy() invoked on it can be created again with a new call to create() (and then started again with a start() call).

Although technically not part of the API, the mode in which the cache is configured to operate affects the cluster-wide behavior of any put or remove operation, so we'll briefly mention the various modes here.

JBoss Cache modes are denoted by the org.jboss.cache.config.Configuration.CacheMode enumeration. They consist of:

See the chapter on Clustering for more details on how the cache's mode affects behavior. See the chapter on Configuration for info on how to configure things like the cache's mode.

The @org.jboss.cache.notifications.annotation.CacheListener annotation is a convenient mechanism for receiving notifications from a cache about events that happen in the cache. Classes annotated with @CacheListener need to be public classes. In addition, the class needs to have one or more methods annotated with one of the method-level annotations (in the org.jboss.cache.notifications.annotation package). Methods annotated as such need to be public, have a void return type, and accept a single parameter of type org.jboss.cache.notifications.event.Event or one of it's subtypes.

Refer to the javadocs on the annotations as well as the Event subtypes for details of what is passed in to your method, and when.

Example:



   @CacheListener
   public class MyListener
   {
      @CacheStarted
      @CacheStopped
      public void cacheStartStopEvent(Event e)
      {
         switch (e.getType())
         {
            case Event.Type.CACHE_STARTED:
               System.out.println("Cache has started");
               break;
            case Event.Type.CACHE_STOPPED:
               System.out.println("Cache has stopped");
               break;
         }
      }
      @NodeCreated
      @NodeRemoved
      @NodeVisited
      @NodeModified
      @NodeMoved
      public void logNodeEvent(NodeEvent ne)
      {
         log("An event on node " + ne.getFqn() + " has occured");
      }
   }
         

Cache loaders are an important part of JBoss Cache. They allow persistence of nodes to disk or to remote cache clusters, and allow for passivation when caches run out of memory. In addition, cache loaders allow JBoss Cache to perform 'warm starts', where in-memory state can be preloaded from persistent storage. JBoss Cache ships with a number of cache loader implementations.

These CacheLoaders, along with advanced aspects and tuning issues, are discussed in the chapter dedicated to CacheLoaders .

Eviction policies are the counterpart to CacheLoaders. They are necessary to make sure the cache does not run out of memory and when the cache starts to fill, the eviction algorithm running in a separate thread offloads in-memory state to the CacheLoader and frees up memory. Eviction policies can be configured on a per-region basis, so different subtrees in the cache could have different eviction preferences. JBoss Cache ships with several eviction policies:

Detailed configuration and implementing custom eviction policies are discussed in the chapter dedicated to eviction policies. .



[1] http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossClusteringPatternFarCache