JBoss.orgCommunity Documentation
When used in a standalone Java program, all that needs to be done is to instantiate the cache using the
CacheFactory
and a
Configuration
instance or an XML file, as discussed
in the
User API
and
Configuration
chapters.
The same techniques can be used when an application running in an application
server wishes to programatically deploy a cache rather than relying on an application server's
deployment features. An example of this would be
a webapp deploying a cache via a
javax.servlet.ServletContextListener
.
If, after deploying your cache you wish to expose a management interface to it in JMX, see the section on Programatic Registration in JMX .
If JBoss Cache is run in JBoss AS then the 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 JBoss Cache's
standard XML configuration file (as shown in the
Configuration Reference
) 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
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 JBoss Cache 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 JBoss Cache 2.0 instance in JBoss AS 4.x (at least in 4.2.0.GA; other AS releases are completely untested). However, the significant API changes between the JBoss Cache 2.x and 1.x releases mean none of the standard AS 4.x clustering services (e.g. http session replication) that rely on JBoss Cache will work with JBoss Cache 2.x. Also, be aware that usage of JBoss Cache 2.x in AS 4.x is not something the JBoss 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.jmx.CacheJmxWrapper
. This is the
class JBoss Cache uses to handle JMX integration; the
Cache
itself does not expose an MBean
interface. See the
JBoss Cache MBeans section
for more on the
CacheJmxWrapper
.
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=Cache");
CacheJmxWrapperMBean cacheWrapper =
(CacheJmxWrapperMBean) MBeanServerInvocationHandler.newProxyInstance(server, on,
CacheJmxWrapperMBean.class, false);
Cache cache = cacheWrapper.getCache();
Node root = cache.getRoot(); // etc etc
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
CacheJmxWrapper
is obtained,
the
getCache()
will return a reference to the
Cache
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
Cache
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 example
-beans.xml
file. 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">
<!-- Externally injected services -->
<property name="runtimeConfig">
<bean name="ExampleCacheRuntimeConfig" class="org.jboss.cache.config.RuntimeConfig">
<property name="transactionManager">
<inject bean="jboss:service=TransactionManager"
property="TransactionManager"/>
</property>
<property name="muxChannelFactory"><inject bean="JChannelFactory"/></property>
</bean>
</property>
<property name="multiplexerStack">udp</property>
<property name="clusterName">Example-EntityCache</property>
<!--
Node locking level : SERIALIZABLE
REPEATABLE_READ (default)
READ_COMMITTED
READ_UNCOMMITTED
NONE
-->
<property name="isolationLevel">REPEATABLE_READ</property>
<!-- Valid modes are LOCAL
REPL_ASYNC
REPL_SYNC
-->
<property name="cacheMode">REPL_SYNC</property>
<!-- The max amount of time (in milliseconds) we wait until the
initial state (ie. the contents of the cache) are retrieved from
existing members in a clustered environment
-->
<property name="initialStateRetrievalTimeout">15000</property>
<!-- Number of milliseconds to wait until all responses for a
synchronous call have been received.
-->
<property name="syncReplTimeout">20000</property>
<!-- Max number of milliseconds to wait for a lock acquisition -->
<property name="lockAcquisitionTimeout">15000</property>
<property name="exposeManagementStatistics">true</property>
<!-- Must be true if any entity deployment uses a scoped classloader -->
<property name="useRegionBasedMarshalling">true</property>
<!-- Must match the value of "useRegionBasedMarshalling" -->
<property name="inactiveOnStartup">true</property>
<!-- Specific eviction policy configurations. This is LRU -->
<property name="evictionConfig">
<bean name="ExampleEvictionConfig"
class="org.jboss.cache.config.EvictionConfig">
<property name="defaultEvictionPolicyClass">
org.jboss.cache.eviction.LRUPolicy
</property>
<property name="wakeupIntervalSeconds">5</property>
<property name="evictionRegionConfigs">
<list>
<bean name="ExampleDefaultEvictionRegionConfig"
class="org.jboss.cache.config.EvictionRegionConfig">
<property name="regionName">/_default_</property>
<property name="evictionPolicyConfig">
<bean name="ExampleDefaultLRUConfig"
class="org.jboss.cache.eviction.LRUConfiguration">
<property name="maxNodes">5000</property>
<property name="timeToLiveSeconds">1000</property>
</bean>
</property>
</bean>
</list>
</property>
</bean>
</property>
</bean>
<!-- Factory to build the Cache. -->
<bean name="DefaultCacheFactory" class="org.jboss.cache.DefaultCacheFactory">
<constructor factoryClass="org.jboss.cache.DefaultCacheFactory"
factoryMethod="getInstance"/>
</bean>
<!-- The cache itself -->
<bean name="ExampleCache" class="org.jboss.cache.Cache">
<constructor factoryMethod="createCache">
<factory bean="DefaultCacheFactory"/>
<parameter class="org.jboss.cache.config.Configuration"><inject bean="ExampleCacheConfig"/></parameter>
<parameter class="boolean">false</false>
</constructor>
</bean>
</deployment>
See the JBoss Microcontainer documentation
[2]
for details on the above syntax. Basically, each
bean
element represents an object; most going to create a
Configuration
and its
constituent parts
.
An interesting thing to note in the above example is the use of the
RuntimeConfig
object. External resources like
a
TransactionManager
and a JGroups
ChannelFactory
that are visible to the
microcontainer are dependency injected into the
RuntimeConfig
.
The assumption here is that in some other deployment descriptor in the AS,
the referenced beans have been described.
With the 1.x JBoss Cache releases, a proxy to the cache could be bound
into JBoss AS's JNDI tree using the AS's
JRMPProxyFactory
service. With JBoss Cache 2.x, this no longer works. An alternative
way of doing a similar thing with a POJO (i.e. non-JMX-based) service
like a
Cache
is under development by the JBoss AS
team
[3]
. That feature is not available as of the time of this writing,
although it will be completed before AS 5.0.0.GA is released.
We will add a wiki page describing how to use it once it becomes available.
JBoss Cache includes JMX MBeans to expose cache functionality and provide statistics that can be used to analyze cache operations. JBoss Cache can also broadcast cache events as MBean notifications for handling via JMX monitoring tools.
JBoss Cache provides an MBean that can be registered with your environments JMX server to allow access
to the cache instance via JMX. This MBean is the
org.jboss.cache.jmx.CacheJmxWrapper
.
It is a StandardMBean, so it's MBean interface is
org.jboss.cache.jmx.CacheJmxWrapperMBean
.
This MBean can be used to:
Cache
.
Cache
.
See the
CacheJmxWrapperMBean
javadoc for more details.
It is important to note a significant architectural difference between JBoss Cache 1.x and 2.x. In 1.x,
the old
TreeCache
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
Cache
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
Cache
API is no longer exposed
through JMX. For example, it is no longer possible to invoke a cache
put
or
get
via the JMX interface.
If a
CacheJmxWrapper
is registered, JBoss Cache also provides MBeans
for each interceptor configured in the cache's interceptor stack. These
MBeans are used to capture and expose statistics related to cache operations. They are hierarchically
associated with the
CacheJmxWrapper
MBean and have service names that reflect this relationship. For
example, a replication interceptor MBean for the
jboss.cache:service=TomcatClusteringCache
instance will be
accessible through the service named
jboss.cache:service=TomcatClusteringCache,cache-interceptor=ReplicationInterceptor
.
The best way to ensure the
CacheJmxWrapper
is registered
in JMX depends on how you are deploying your cache:
Simplest way to do this is to create your
Cache
and pass it to the
CacheJmxWrapper
constructor.
CacheFactory factory = new DefaultCacheFactory();
// Build but don't start the cache
// (although it would work OK if we started it)
Cache cache = factory.createCache("cache-configuration.xml", false);
CacheJmxWrapperMBean wrapper = new CacheJmxWrapper(cache);
MBeanServer server = getMBeanServer(); // however you do it
ObjectName on = new ObjectName("jboss.cache:service=TreeCache");
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
CacheJmxWrapper
. The wrapper
will construct the
Cache
:
Configuration config = buildConfiguration(); // whatever it does
CacheJmxWrapperMBean wrapper = new CacheJmxWrapper(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
Cache cache = wrapper.getCache();
... use the cache
... on application shutdown
wrapper.stop();
wrapper.destroy();
When you
deploy your cache in JBoss AS using a -service.xml file
,
a
CacheJmxWrapper
is automatically registered. There is no need
to do anything further. The
CacheJmxWrapper
is accessible from an MBean server
through the service name specified in the cache configuration file's
mbean
element.
CacheJmxWrapper
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
CacheJmxWrapper
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>
<!-- Factory to build the Cache. -->
<bean name="DefaultCacheFactory" class="org.jboss.cache.DefaultCacheFactory">
<constructor factoryClass="org.jboss.cache.DefaultCacheFactory"
factoryMethod="getInstance"/>
</bean>
<!-- The cache itself -->
<bean name="ExampleCache" class="org.jboss.cache.CacheImpl">
<constructor factoryMethod="createnewInstance">
<factory bean="DefaultCacheFactory"/>
<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=ExampleTreeCache",
exposedInterface=org.jboss.cache.jmx.CacheJmxWrapperMBean.class,
registerDirectly=true)</annotation>
<constructor>
<parameter><inject bean="ExampleCache"/></parameter>
</constructor>
</bean>
</deployment>
As discussed in the
Programatic Registration
section,
CacheJmxWrapper
can do the work of building,
creating and starting the
Cache
if it is provided
with a
Configuration
. With the microcontainer,
this is the preferred approach, as it saves the boilerplate XML
needed to create the
CacheFactory
:
<?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.jmx.CacheJmxWrapper">
<annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.cache:service=ExampleTreeCache",
exposedInterface=org.jboss.cache.jmx.CacheJmxWrapperMBean.class,
registerDirectly=true)</annotation>
<constructor>
<parameter><inject bean="ExampleCacheConfig"/></parameter>
</constructor>
</bean>
</deployment>
JBoss Cache captures statistics in its interceptors and exposes the statistics through interceptor
MBeans. Gathering of statistics is enabled by default; this can be disabled for a specific cache
instance through the
ExposeManagementStatistics
configuration attribute. Note that
the majority of the statistics are provided by the
CacheMgmtInterceptor
,
so this MBean is the most significant in this regard. If you want to disable all statistics for performance
reasons, you set
ExposeManagementStatistics
to
false
as this will
prevent the
CacheMgmtInterceptor
from being included in the cache's interceptor stack
when the cache is started.
If a
CacheJmxWrapper
is registered with JMX, the wrapper also ensures that
an MBean is registered in JMX for each interceptor that exposes statistics
[4]
.
Management tools can then access those MBeans to examine the statistics. See the section in the
JMX Reference chapter
pertaining to the
statistics that are made available via JMX.
The name under which the interceptor MBeans will be registered is derived by taking the
ObjectName
under which the
CacheJmxWrapper
is
registered and adding a
cache-interceptor
attribute key whose value
is the non-qualified name of the interceptor class. So, for example, if the
CacheJmxWrapper
were registered under
jboss.cache:service=TreeCache
, the name of the
CacheMgmtInterceptor
MBean would be
jboss.cache:service=TreeCache,cache-interceptor=CacheMgmtInterceptor
.
Each interceptor's MBean exposes a
StatisticsEnabled
attribute that can be used to disable maintenance of statistics for
that interceptor. In addition, each interceptor MBean provides the following common operations and
attributes.
dumpStatistics
- returns a
Map
containing the interceptor's attributes and values.
resetStatistics
- resets all statistics maintained by the interceptor.
setStatisticsEnabled(boolean)
- allows statistics to be disabled for a specific interceptor.
JBoss Cache users can register a listener to receive cache events described earlier in the
User API
chapter. Users can alternatively utilize the cache's management information infrastructure to receive these
events
via JMX notifications. Cache events are accessible as notifications by registering a
NotificationListener
for the
CacheJmxWrapper
.
See the section in the
JMX Reference chapter
pertaining
to JMX notifications for a list of notifications that can be received through the
CacheJmxWrapper
.
The following is an example of how to programmatically receive cache notifications when running in a JBoss AS environment. In this example, the client uses a filter to specify which events are of interest.
MyListener listener = new MyListener();
NotificationFilterSupport filter = null;
// get reference to MBean server
Context ic = new InitialContext();
MBeanServerConnection server = (MBeanServerConnection)ic.lookup("jmx/invoker/RMIAdaptor");
// get reference to CacheMgmtInterceptor MBean
String cache_service = "jboss.cache:service=TomcatClusteringCache";
ObjectName mgmt_name = new ObjectName(cache_service);
// configure a filter to only receive node created and removed events
filter = new NotificationFilterSupport();
filter.disableAllTypes();
filter.enableType(CacheNotificationBroadcaster.NOTIF_NODE_CREATED);
filter.enableType(CacheNotificationBroadcaster.NOTIF_NODE_REMOVED);
// register the listener with a filter
// leave the filter null to receive all cache events
server.addNotificationListener(mgmt_name, listener, filter, null);
// ...
// on completion of processing, unregister the listener
server.removeNotificationListener(mgmt_name, listener, filter, null);
The following is the simple notification listener implementation used in the previous example.
private class MyListener implements NotificationListener, Serializable
{
public void handleNotification(Notification notification, Object handback)
{
String message = notification.getMessage();
String type = notification.getType();
Object userData = notification.getUserData();
System.out.println(type + ": " + message);
if (userData == null)
{
System.out.println("notification data is null");
}
else if (userData instanceof String)
{
System.out.println("notification data: " + (String) userData);
}
else if (userData instanceof Object[])
{
Object[] ud = (Object[]) userData;
for (Object data : ud)
{
System.out.println("notification data: " + data.toString());
}
}
else
{
System.out.println("notification data class: " + userData.getClass().getName());
}
}
}
Note that the JBoss Cache management implementation only listens to cache events after a client registers to receive MBean notifications. As soon as no clients are registered for notifications, the MBean will remove itself as a cache listener.
JBoss Cache MBeans are easily accessed when running cache instances in an application server that provides an MBean server interface such as JBoss JMX Console. Refer to your server documentation for instructions on how to access MBeans running in a server's MBean container.
In addition, though, JBoss Cache MBeans are also accessible when running in a non-server environment if the JVM is JDK 5.0 or later. When running a standalone cache in a JDK 5.0 environment, you can access the cache's MBeans as follows.
-Dcom.sun.management.jmxremote
when starting the JVM
where the cache will run.
jconsole
utility, located in your JDK's
/bin
directory.
Note that the
jconsole
utility will automatically register as a listener for cache notifications when
connected to a JVM running JBoss Cache instances.
The following figure shows cache interceptor MBeans in
jconsole
. Cache statistics are displayed
for the
CacheMgmtInterceptor
:
[2] http://labs.jboss.com/jbossmc/docs
[3] http://jira.jboss.com/jira/browse/JBAS-4456
[4]
Note that if the
CacheJmxWrapper
is not registered in JMX, the
interceptor MBeans will not be registered either. The JBoss Cache 1.4 releases
included code that would try to "discover" an
MBeanServer
and
automatically register the interceptor MBeans with it. For JBoss Cache 2.x we decided
that this sort of "discovery" of the JMX environment was beyond the proper scope of
a caching library, so we removed this functionality.