JBoss TreeCache/TreeCacheAop Tutorial

Ben Wang, ben.wang@jboss.org
Bela Ban, bela@jboss.org


Introduction

Jboss TreeCache (and TreeCacheAop) is a replicated (synchronous or asynchronous) and transactional cache with aspect-oriented programming (AOP) capability. In this tutorial, we will demonstrate the usage of the cache with and without AOP. For details of the usage and APIs, please refer to the user manuals for TreeCache and TreeCacheAop.

Scope

Scope of this tutorial includes:

Configuration

First download the standalone TreeCache code from here. Unzip it, and you will get a root directory (jboss-cache in our example).

The configuration files are located under the etc directory. You can modify the behavior of TreeCache through editing the various configuration files.

Script

The script files that are needed (located under install directory) in this tutorial are:

Example POJO

The example POJO classes used for TreeCacheAop demo are: Person and Address. They are located under examples/org/jboss/test/cache/test/standAloneAop directory. Person has attributes of String age, Address addr, List languages, etc. We will demonstrate that once you put the POJO instance in the cache, plain get/set POJO methods will be intercepted by the cache.

Here is the snippet of the class definition for Person and Address.

public class Person {
String name=null;
int age=0;
Map hobbies=null;
Address address=null;
Set skills;
List languages;

public String getName() {
return name;
}

public void setName(String name) {
this.name=name;
}
...
}
and
public class Address {
String street=null;
String city=null;
int zip=0;

public String getStreet() {
return street;
}

public void setStreet(String street) {
this.street=street;
}
...
}

Demo

To run the demo, you will need at least two windows: one to peruse the cache contents (plus non-aop operations) and the other to operate the cache directly. Of course, you can also open more than one GUI window to see the cache replication at work to multiple members. You will also need to run the scripts under jboss-cache installation directory after you unzip the release package (jboss-cache-dist.zip). Also note that for each demo examples, it'd be best if you re-start the whole setup.

The two demo programs to run are:

Plain cache

Once you are in the shell, you can either execute the script to populate the cache, or type it in manually by command line. To run the script, type sourceRelative("plain.bsh"); under the interactive BSH shell. For this to work, you'll need to have your working directory set to the directory in which plain.bsh resides (otherwise give the full pathname of plain.bsh). Basically, the script will create cache entries that will be replicated onto the GUI. Here are the snippets for the script:
import org.jboss.cache.*;
show(); // verbose mode
tree = new TreeCache();
config = new PropertyConfigurator();
// configure tree cache. Needs to be in the classpath
config.configure(tree, "META-INF/replSync-service.xml");
tree.start(); // kick start tree cache
tree.put("/a/b/c", "ben", "me"); // create a cache entry.
// Node "/a/b/c" will be created if not yet existed.

You should see in the GUI that a new entry of /a/b/c has been created. Click on the node c to see the content. You can modify the contents from the GUI as well. To create another node, for example, you can type in the shell:

tree.put("/a/b/c/d", "JBoss", "Open Source");
and to query the node:
tree.get("/a/b/c/d", "JBoss");

CacheAop

Once you are in the shell, type sourceRelative("aop.bsh"); to execute the shell script. Basically, aop.bsh illustrates the steps to instantiate a cache, configure it, and then create entries under it. Here are the snippets:
import org.jboss.cache.PropertyConfigurator;
import org.jboss.cache.aop.TreeCacheAop;
import org.jboss.test.cache.test.standAloneAop.Person;
import org.jboss.test.cache.test.standAloneAop.Address;
show();  // verbose mode
tree = new TreeCacheAop();
config = new PropertyConfigurator();
// configure tree cache.
config.configure(tree, "META-INF/replSync-service.xml");
joe = new Person(); // instantiate a Person object named joe
joe.setName("Joe Black");
joe.setAge(31);

addr = new Address(); // instantiate a Address object named addr
addr.setCity("Sunnyvale");
addr.setStreet("123 Albert Ave");
addr.setZip(94086);

joe.setAddress(addr); // set the address reference
tree.start();  // kick start tree cache
tree.putObject("/aop/joe", joe); // add aop sanctioned object (and sub-objects) into cache.
// since it is aop-sanctioned, use of plain get/set methods will take care of cache contents automatically. joe.setAge(41);

Note the API needed to put the object (and its dependent ones) into cache is putObject. Once the second window finishes execution, you should see the first GUI window has been populated with entries of /aop/joe/address. Click on each tree node will display different values associated with that node.

Next step to see AOP in action, you can do plain get/set methods without ever worrying about put it in the cache. For example, you can do in the shell window joe.setAge(20); and see that GUI gets updated with the age field automatically. Also to demonstrate the object graph replication, you can modify Joe's address and see the cache will update it automatically. For example, type addr.setCity("San Jose"); in the interactive shell, you should see in the GUI that the address got modified.

Finally, TreeCacheAop also supports get/set with parameter type of Collection classes (i.e., List, Map, and Set). For example, type the following in the shell command line:
lang = new ArrayList();
lang.add("Ensligh");
lang.add("Mandarin");

joe.setLanguages(lang);
You should see in the GUI window that the languages list gets populated.

CacheAop with Transaction

To see TreeCache transaction at work, you start with the same setup with last section except you load the bsh of aopWithTx.bsh instead of aop.bsh. The additional snippets are:

import org.jboss.cache.PropertyConfigurator;
import org.jboss.cache.aop.TreeCacheAop;
import org.jboss.test.cache.test.standAloneAop.Person;
import org.jboss.test.cache.test.standAloneAop.Address;
// Tx imports
import javax.transaction.UserTransaction;
import javax.naming.*;
import org.jboss.cache.transaction.DummyTransactionManager;
show();  // verbose mode // Set up transaction manager
DummyTransactionManager.getInstance();
prop = new Properties();
prop.put(Context.INITIAL_CONTEXT_FACTORY,
    "org.jboss.cache.transaction.DummyContextFactory");
tx = (UserTransaction)new InitialContext(prop).lookup("UserTransaction");
tree = new TreeCacheAop();

config = new PropertyConfigurator();
// configure tree cache.
config.configure(tree, "META-INF/replSync-service.xml");

joe = new Person();
joe.setName("Joe Black");
joe.setAge(31);

addr = new Address();
addr.setCity("Sunnyvale");
addr.setStreet("123 Albert Ave");
addr.setZip(94086);

joe.setAddress(addr);
tree.start();  // kick start tree cache
tree.putObject("/aop/joe", joe); // add aop sanctioned object

// since it is aop-sanctioned, use of plain get/set methods will take care of cache contents automatically.
// Also it is transacted
tx.begin();
joe.setAge(41);
joe.getAddress().setZip(95124);
tx.commit();

In this example, a default dummy transaction manager is used.

You can also try the rollback as:
tx.begin();
addr.setZip(95131);
tx.rollback();

Troubleshooting

Here are some tips for troubleshooting, if you encounter problems during this demo.