JBoss.org Community Documentation
Since POJO Cache uses Core Cache for the underlying node replication, transaction, locking, and passivation behavior, the configuration is mostly the same.
When a PojoCache instance is obtained from a PojoCacheFactory, it is required that the
either a org.jboss.cache.config.Configuration
object is passed, or more typically
a String indicating the location on the classpath or filesystem of an xml configuration file is provided.
In the latter case, PojoCacheFactory will parse the xml to create a Configuration
.
PojoCache will simply pass the resulting Configuration
to the underlying Core Cache
implementation.
For details on the configuration please see the "Configuration" chapter in the
the JBoss Cache User Guide.
A common use-case is to configure the underlying Core Cache to enable passivation. Passivation is a feature used to reduce cache memory usage by evicting stale data that can later be reloaded. In JBoss Cache, it is done via a combination of an eviction policy and a cache loader. That is, when a node is evicted from the Cache's in-memory store, it will be stored in a persistent store by the cache loader. When the node is requested again, it will be loaded from the persistent store and stored into memory.
There is a restriction, however. Since POJO Cache maps object data into an internal area, there are
two places that have object information. One is under the regular String ID that the user specifies, and
the other is located under /__JBossInternal__
. Therefore, to maintain consistentency,
when you specify the eviction region, you can only specify one global (i.e., /_default_
)
region. This way, when the nodes associated with a POJO are passivated, they will do so across the whole
region.
Below is a snippet from a cache configuration xml illustrating how the eviction policy along with cache loader can be configured. Please note that this is simply an aspect of the underlying Cache. That is, PojoCache layer is agnostic to this behavior.
<attribute name="EvictionPolicyConfig">
<config>
<attribute name="wakeUpIntervalSeconds">5</attribute>
<attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
<!-- Cache wide default -->
<region name="/_default_">
<attribute name="maxNodes">5000</attribute>
<attribute name="timeToLiveSeconds">3</attribute>
</region>
</config>
</attribute>
<attribute name="CacheLoaderConfiguration">
<config>
<passivation>true</passivation>
<preload>/</preload>
<shared>false</shared>
<!-- we can now have multiple cache loaders, which get chained -->
<cacheloader>
<class>org.jboss.cache.loader.FileCacheLoader</class>
<!-- whether the cache loader writes are asynchronous -->
<async>false</async>
<!-- only one cache loader in the chain may set fetchPersistentState to true.
An exception is thrown if more than one cache loader sets this to true. -->
<fetchPersistentState>true</fetchPersistentState>
<!-- determines whether this cache loader ignores writes - defaults to false. -->
<ignoreModifications>false</ignoreModifications>
</cacheloader>
</config>
</attribute>
Another way to support multiple regions in eviction is to use region-based marshalling. See the "Architecture" chapter in the JBoss Cache User Guide for more information on region-based marshalling. When the Cache uses region-based marshalling, POJO Cache will store internal node data on the region that is specified. This allows for a more flexible eviction policy.
POJO Cache supplies a pojocache-aop.xml
that is required to be set via a
system property: jboss.aop.path
during compile- or load-time, or placed in
the user's classpath. The file now consists
of the interceptor stack specification, as well as annotations for POJO instrumentation. It is listed fully in the
Appendix section. Note that the file should not normally need to be modified. Only an advanced use-case
would require changes.
There are a number of ways to deploy POJO Cache:
Simply instantiate a PojoCacheFactory and invoke one of the
overloaded createCache
methods shown in the
API Overview.
If PojoCache is run in JBoss AS then your cache can be deployed as an
MBean simply by copying a standard cache configuration file to the server's
deploy
directory. The standard format of PojoCache's
standard XML configuration file (as shown in the
Appendix) is the same
as a JBoss AS MBean deployment descriptor, so the AS's SAR Deployer has
no trouble handling it. Also, you don't have to place the configuration
file directly in deploy
; you can package it along
with other services or JEE components in a SAR or EAR.
In AS 5, if you're using a server config based on the standard
all
config, then that's all you need to do; all required
jars will be on the classpath. Otherwise, you will need to ensure
pojocache.jar
, jbosscache.jar
and jgroups-all.jar
are on the classpath. You may
need to add other jars if you're using
things like JdbmCacheLoader
. The simplest way to do
this is to copy the jars from the PojoCache distribution's
lib
directory to the server config's lib
directory. You could also package the jars with the configuration file
in Service Archive (.sar) file or an EAR.
It is possible, to deploy a POJO Cache 2.0 instance in JBoss AS 4.x However, the significant API changes between the 2.x and 1.x releases mean none of the standard AS 4.x clustering services (e.g. http session replication) that rely on the 1.x API will work with PojoCache 2.x. Also, be aware that usage of PojoCache 2.x in AS 4.x is not something the cache developers are making any significant effort to test, so be sure to test your application well (which of course you're doing anyway.)
Note in the example
the value of the mbean
element's
code
attribute:
org.jboss.cache.pojo.jmx.PojoCacheJmxWrapper
. This is the
class JBoss Cache uses to handle JMX integration; the
PojoCache itself does not expose an MBean
interface. See the
JBoss Cache MBeans section
for more on the PojoCacheJmxWrapper.
Once your cache is deployed, in order to use it with an in-VM client such as a servlet, a JMX proxy can be used to get a reference to the cache:
MBeanServer server = MBeanServerLocator.locateJBoss();
ObjectName on = new ObjectName("jboss.cache:service=PojoCache");
PojoCacheJmxWrapperMBean cacheWrapper =
(PojoCacheJmxWrapperMBean) MBeanServerInvocationHandler.newProxyInstance(server, on,
PojoCacheJmxWrapperMBean.class, false);
PojoCache cache = cacheWrapper.getPojoCache();
The MBeanServerLocator class is a helper to find the (only) JBoss
MBean server inside the current JVM. The
javax.management.MBeanServerInvocationHandler
class'
newProxyInstance
method creates a
dynamic proxy implementing the given interface and uses JMX to
dynamically dispatch methods invoked against the generated interface
to the MBean. The name used to look up the MBean is the same as defined
in the cache's configuration file.
Once the proxy to the PojoCacheJmxWrapper
is obtained,
the getPojoCache()
will return a reference to the
PojoCache itself.
Beginning with AS 5, JBoss AS also supports deployment of POJO services via
deployment of a file whose name ends with -beans.xml
.
A POJO service is one whose implementation is via a "Plain Old Java Object",
meaning a simple java bean that isn't required to implement any special
interfaces or extend any particular superclass. A PojoCache
is a POJO service, and all the components in a Configuration
are also POJOS, so deploying a cache in this way is a natural step.
Deployment of the cache is done using the JBoss Microcontainer that forms the
core of JBoss AS. JBoss Microcontainer is a sophisticated IOC framework
(similar to Spring). A -beans.xml
file is basically
a descriptor that tells the IOC framework how to assemble the various
beans that make up a POJO service.
The rules for how to deploy the file, how to package it, how to ensure the required jars are on the classpath, etc. are the same as for a JMX-based deployment.
Following is an abbreviated example -beans.xml
file.
The details of building up the Configuration are omitted; see the
"Deploying JBoss Cache" chapter in the JBoss Cache User Guide for
a more complete example. If you look in the
server/all/deploy
directory of an AS 5
installation, you can find several more examples.
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<!-- First we create a Configuration object for the cache -->
<bean name="ExampleCacheConfig"
class="org.jboss.cache.config.Configuration">
... details omitted
</bean>
<!-- The cache itself. -->
<bean name="ExampleCache" class="org.jboss.cache.pojo.impl.PojoCacheImpl">
<constructor factoryClass="org.jboss.cache.pojo.PojoCacheFactory
factoryMethod="createCache">
<parameter><inject bean="ExampleCacheConfig"/></parameter>
<parameter>false</false>
</constructor>
</bean>
</deployment>
An interesting thing to note in the above example is the difference
between POJO Cache and a plain Cache in the use of a factory to
create the cache. (See the "Deploying JBoss Cache" chapter in the
JBoss Cache User Guide for the comparable plain Cache example.) The
PojoCacheFactory exposes static methods for creating a PojoCache;
as a result there is no need to add a separate bean
element for the factory. Core Cache's
DefaultCacheFactory
creates caches from a singleton
instance, requiring a bit more boilerplate in the config file.
POJO Cache provides an MBean that can be registered with your environment's JMX server to allow access
to the cache instance via JMX. This MBean is the org.jboss.cache.pojo.jmx.PojoCacheJmxWrapper
.
It is a StandardMBean, so it's MBean interface is org.jboss.cache.pojo.jmx.PojoCacheJmxWrapperMBean
.
This MBean can be used to:
See the PojoCacheJmxWrapperMBean
javadoc for more details.
It is important to note a significant architectural difference between PojoCache 1.x and 2.x. In 1.x,
the old TreeCacheAop
class was itself an MBean, and essentially exposed the cache's entire
API via JMX. In 2.x, JMX has been returned to it's fundamental role as a management layer. The
PojoCache object itself is completely unaware of JMX; instead JMX functionality is added
through a wrapper class designed for that purpose. Furthermore, the interface exposed through JMX
has been limited to management functions; the general PojoCache API is no longer exposed
through JMX. For example, it is no longer possible to invoke a cache attach
or
detach
via the JMX interface.
If a PojoCacheJmxWrapper
is registered, the wrapper also registers MBeans
for the underlying plain Cache and for each interceptor configured in the cache's interceptor stack.
These MBeans are used to capture and expose statistics related to cache operations; see the
JBoss Cache User Guide for more. They are hierarchically
associated with the PojoCacheJmxWrapper
MBean and have service names that
reflect this relationship. For
example, a plain Cache associated with a jboss.cache:service=PojoCache
will be
accessible through an mbean named jboss.cache:service=PojoCache,cacheType=Cache
.
The replication interceptor MBean for that cache will be accessible through the mbean named
jboss.cache:service=PojoCache,cacheType=Cache,cache-interceptor=ReplicationInterceptor
.
The best way to ensure the PojoCacheJmxWrapper
is registered
in JMX depends on how you are deploying your cache:
Simplest way to do this is to create your PojoCache
and pass it to the PojoCacheJmxWrapper
constructor.
// Build but don't start the cache
// (although it would work OK if we started it)
PojoCache cache = PojoCacheFactory.createCache("cache-configuration.xml", false);
PojoCacheJmxWrapperMBean wrapper = new PojoCacheJmxWrapper(cache);
MBeanServer server = getMBeanServer(); // however you do it
ObjectName on = new ObjectName("jboss.cache:service=PojoCache");
server.registerMBean(wrapper, on);
// Invoking lifecycle methods on the wrapper results
// in a call through to the cache
wrapper.create();
wrapper.start();
... use the cache
... on application shutdown
// Invoking lifecycle methods on the wrapper results
// in a call through to the cache
wrapper.stop();
wrapper.destroy();
Alternatively, build a Configuration
object
and pass it to the PojoCacheJmxWrapper
. The wrapper
will construct the PojoCache
:
Configuration config = buildConfiguration(); // whatever it does
PojoCacheJmxWrapperMBean wrapper = new PojoCacheJmxWrapper(config);
MBeanServer server = getMBeanServer(); // however you do it
ObjectName on = new ObjectName("jboss.cache:service=TreeCache");
server.registerMBean(wrapper, on);
// Call to wrapper.create() will build the Cache if one wasn't injected
wrapper.create();
wrapper.start();
// Now that it's built, created and started, get the cache from the wrapper
PojoCache cache = wrapper.getPojoCache();
// ... use the cache
// ... on application shutdown
wrapper.stop();
wrapper.destroy();
When you
deploy your cache in JBoss AS using a -service.xml file,
a PojoCacheJmxWrapper
is automatically registered. There is no need
to do anything further. The PojoCacheJmxWrapper
is accessible
through the service name specified in the cache configuration file's mbean
element.
PojoCacheJmxWrapper
is a POJO, so the microcontainer
has no problem creating one. The trick is
getting it to register your bean in JMX. This can be done by
specifying the org.jboss.aop.microcontainer.aspects.jmx.JMX
annotation on the PojoCacheJmxWrapper
bean:
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<!-- First we create a Configuration object for the cache -->
<bean name="ExampleCacheConfig"
class="org.jboss.cache.config.Configuration">
... build up the Configuration
</bean>
<!-- The cache itself. -->
<bean name="ExampleCache" class="org.jboss.cache.pojo.impl.PojoCacheImpl">
<constructor factoryClass="org.jboss.cache.pojo.PojoCacheFactory
factoryMethod="createCache">
<parameter><inject bean="ExampleCacheConfig"/></parameter>
<parameter>false</false>
</constructor>
</bean>
<!-- JMX Management -->
<bean name="ExampleCacheJmxWrapper" class="org.jboss.cache.jmx.CacheJmxWrapper">
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(
name="jboss.cache:service=ExamplePojoCache",
exposedInterface=org.jboss.cache.pojo.jmx.PojoCacheJmxWrapperMBean.class,
registerDirectly=true)
</annotation>
<constructor>
<parameter><inject bean="ExampleCache"/></parameter>
</constructor>
</bean>
</deployment>
As discussed in the Programatic Registration
section, PojoCacheJmxWrapper
can do the work of building,
creating and starting the PojoCache if it is provided with a Configuration
:
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<!-- First we create a Configuration object for the cache -->
<bean name="ExampleCacheConfig"
class="org.jboss.cache.config.Configuration">
... build up the Configuration
</bean>
<bean name="ExampleCache" class="org.jboss.cache.pojo.jmx.PojoCacheJmxWrapper">
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(
name="jboss.cache:service=ExamplePojoCache",
exposedInterface=org.jboss.cache.pojo.jmx.PojoCacheJmxWrapperMBean.class,
registerDirectly=true)
</annotation>
<constructor>
<parameter><inject bean="ExampleCacheConfig"/></parameter>
</constructor>
</bean>
</deployment>
As mentioned above, the cache exposes a variety of statistical information through its MBeans. It also emits JMX notifications when events occur in the cache. See the JBoss Cache User Guide for more on the statistics and notifications that are available.
The only PojoCache addition to the plain JBoss Cache behavior described in the User Guide is that you can register with the PojoCacheJmxWrapper to get the notifications. There is no requirement to figure out the ObjectName of the underlying cache's CacheJmxWrapper and register with that.