Ben Wang, ben.wang@jboss.org
Bela Ban, bela@jboss.org
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.
etc
directory.
You can modify the behavior of
TreeCache through editing the various
configuration files.
log4j.xml
. Logging output. You can turn on logging
level or change log file
directory (default is /tmp/test.log
).replSync-service.xml
. Tree cache configuration file
(file name is not fixed. You specify the file to be read in in PropertyConfigurator
).
The settings are for
a replicated, synchronous, and transactional cache. The default DummyTransactionManager
is used with a transaction
isolation level of REPEATABLE
. For details of the
configuration
parameters, please refer to the user manual.
Note that this file is used in the BSH (BeanShell
) script
to configure the cache.jboss-aop.xml
. AOP pointcut and advice definition
for the example POJO classes, Person
and Address
,
respectively. For
details of how to put your own class
under AOP, please refer to the user manual.
This file is read in when
the process is started.The script files that are needed (located under install directory) in this tutorial are:
build.sh
(or build.bat
for DOS).
Simple build script that wraps around ant
. Users can
simply type sh build.sh
for help. Note from now on, we
will only refer to the Unix version with the understanding that there
is a corresponding DOS counterpart. The same goes for runDemoShell
explained next.runDemoShell.sh
. Simple run script that wraps around
BeanShell
. This is used to operate the replicated
cache through
interactive command line.plain.bsh
. Java codes that instantiate and
configure the cache. It also creates an example cache entry.aop.bsh
. Java codes that instantiate and
configure the aop cache. In addition, it also sets up the example POJO
(plaing old Java object) classes (e.g., Person
and Address
).aopWithTx.bsh
. Same with aop.bsh
except it also
instantiates a transaction context.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;
}
...
}
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:
sh build.sh
to see the
available commands. To run the GUI, type sh build.sh run.aop.demo
.
It will
startup a TreeCacheAop GUI. Later on, you can click on a node to view
the the contents. Note that you can also add/modify the node contents
for non-AOP cache entries. Since the GUI entry only accepts String for
now, operation on aop cache from the GUI will not always work (unless
it is a String
type).sh
runShellDemo.sh
to fire off the BeanShell
interactive command shell (you can use either ^D
or ^Z
in Windows and Unix to exit afterward). You can then read in the Java
code scripts to
showcase the cache capabilities (e.g., plain.bsh
, aop.bsh
,
and aopWithTx.bsh
). See the following for details.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");
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.
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.
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();
Here are some tips for troubleshooting, if you encounter problems during this demo.
JGroups
package. On the output window, you
can see the JGroups
membership view. See if it is updated
when you run the BSH commands. It should show a view with at least two
members. For example, on my window, I see
[java] ** view change: [BWANG-HOME:4381|1] [BWANG-HOME:4381, BWANG-HOME:4383]
with 2 members: 4381 and 4383. On the other hand, if you don't close
the previous running cache instance, the membership view will also
include the previous existing ones. This can corrupt the states. So you
will have to make sure there is no running TreeCache processes before
each demo. If you have problem with this, please consult the JGroups
website.