JBoss.orgCommunity Documentation

Chapter 5. Deploying JBoss Cache

5.1. Standalone Use/Programatic Deployment
5.2. Via JBoss Microcontainer (JBoss AS 5.x)
5.3. Automatic binding to JNDI in JBoss AS
5.4. Runtime Management Information
5.4.1. JBoss Cache MBeans
5.4.2. Registering the CacheJmxWrapper with the MBeanServer
5.4.3. JBoss Cache Statistics
5.4.4. Receiving JMX Notifications
5.4.5. Accessing Cache MBeans in a Standalone Environment using the jconsole Utility

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.

After creation, you could share your cache instance among different application components either by using an IOC container such as Spring, JBoss Microcontainer, etc., or by binding it to JNDI, or simply holding a static reference to the cache.

If, after deploying your cache you wish to expose a management interface to it in JMX, see the section on Programatic Registration in JMX.

Beginning with AS 5, JBoss AS 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.

For each configurable option exposed by the Configuration components, a getter/setter must be defined in the configuration class. This is required so that JBoss Microcontainer can, in typical IOC way, call these methods when the corresponding properties have been configured.

You need to ensure that the jbosscache-core.jar and jgroups.jar libraries are in your server's lib directory. This is usually the case when you use JBoss AS in its all configuration. Note that you will have to bring in any optional jars you require, such as jdbm.jar based on your cache configuration.

The following is an example -beans.xml file. If you look in the server/all/deploy directory of a JBoss 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>
        
      <property name="isolationLevel">REPEATABLE_READ</property>

      <property name="cacheMode">REPL_SYNC</property>

      <property name="initialStateRetrievalTimeout">15000</property>

      <property name="syncReplTimeout">20000</property>

      <property name="lockAcquisitionTimeout">15000</property>
        
      <property name="exposeManagementStatistics">true</property>
   </bean>
   
   <!-- Factory to build the Cache. -->
   <bean name="DefaultCacheFactory" class="org.jboss.cache.DefaultCacheFactory">      
      <constructor factoryClass="org.jboss.cache.DefaultCacheFactory" />
   </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 for details on the above syntax. Basically, each bean element represents an object and is used 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 already been described.

This 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.

The best way to ensure the CacheJmxWrapper is registered in JMX depends on how you are deploying your cache.

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" />
   </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 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.



[1] 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.