4 Replies Latest reply on Feb 23, 2012 8:22 AM by trybik

    Cache 3 + Hibernate 3.3 + JMX/JNDI exposure

    trybik

      Hello,
      sorry for the long explanation, but I wanted to make things clear.

      I am a LAMS developer. Till now, we were using JBoss Cache 1.4.2 on JBoss 4.0.2. It was deployed as a MBean and was made available by JMX as "jboss.cache:service=TreeCache".

      The new idea was to use the latest JBoss Cache 3.1.0.
      We are not using CacheManager, as our needs are small
      and we only have one, local instance of Cache.

      The suggested way of deploying Cache is to use "-jboss-beans.xml"
      deployments. Beans can be exposed to JMX by using
      annotations. I've read this guide:
      http://www.jboss.org/file-access/default/members/jbosscache/freezone/docs/3.1.0.CR1/userguide_en/html_single/index.html#jmx.registration

      For our needs, "lams-cache-jboss-beans.xml" was written.

      <?xml version="1.0" encoding="UTF-8"?>
      
      
      
      <deployment xmlns="urn:jboss:bean-deployer:2.0">
      
       <!-- LAMS TreeCache configuration for JBoss 5 -->
      
       <bean name="LamsCacheConfig"
      
       class="org.jboss.cache.config.Configuration">
      
       <!-- Externally injected services -->
      
       <property name="runtimeConfig">
      
       <bean class="org.jboss.cache.config.RuntimeConfig">
      
       <property name="transactionManager">
      
       <inject bean="jboss:service=TransactionManager"
      
       property="TransactionManager"/>
      
       </property>
      
       <!-- We don't need it
       <property name="muxChannelFactory"><inject bean="JChannelFactory"/></property>
       -->
       </bean>
      
       </property>
      
      
      
       <property name="multiplexerStack">udp</property>
      
      
      
       <property name="clusterName">TreeCache-Cluster</property>
      
      
      
       <property name="isolationLevel">READ_COMMITTED</property>
      
      
      
       <property name="cacheMode">LOCAL</property>
      
      
      
       <property name="stateRetrievalTimeout">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" />
      
      
       <bean name="LamsCache" class="org.jboss.cache.Cache">
      
       <constructor factoryMethod="createCache">
      
       <factory bean="DefaultCacheFactory"/>
      
       <parameter class="org.jboss.cache.config.Configuration"><inject bean="LamsCacheConfig"/></parameter>
      
       <parameter class="boolean">false</parameter>
      
       </constructor>
      
      
      
       </bean>
      
       <bean name="LamsJmxWrapper" class="org.jboss.cache.jmx.CacheJmxWrapper">
      
       <annotation>@org.jboss.aop.microcontainer.aspects.jmx.JMX(name="jboss.cache:service=LamsCache", exposedInterface=org.jboss.cache.jmx.CacheJmxWrapperMBean.class, registerDirectly=true)</annotation>
      
       <constructor>
      
       <parameter><inject bean="LamsCache"/></parameter>
      
       </constructor>
       </bean>
      </deployment>


      But there is problem with Hibernate 3.3 integration. I want to use SharedJBossCacheRegionFactory. It looks for the Cache config file (treecache.xml) and builds its own instance.

      But in LAMS we need access to cache from withing the code too. We have a special website for Admins where they can lookup and manipulate the cache.
      The code used to connect to cache using JMX, similary to this:
      MBeanServer server = JMXUtil.getMBeanServer();
       CacheJmxWrapperMBean wrapper = (CacheJmxWrapperMBean) MBeanServerInvocationHandler.newProxyInstance(
       server, ObjectName.getInstance(cacheObjectName), CacheJmxWrapperMBean.class, false);
       cache = wrapper.getCache();

      So we need a separately deployed Cache instance, like the way we did before.
      It is impossible to expose to JMX the Cache instance itself, as we declare a bean as
      org.jboss.cache.Cache
      which is an interface. Interfaces can not be MBeans, since they do not inherit from Object. In Cache 2, the Cache bean was CacheImpl which was a concrete class. In Cache 3 it is constructed by
      CacheFactory and we have only the interface, which can not be exposed.
      Then, there is CacheJmxWrapper class. It wraps the Cache and allows JMX exposition.

      Since in Hibernate we do not create local instance of Cache, we need to access the deployed one
      somehow. We are left with JndiSharedJBossCacheRegionFactory. It allows accessing Cache instance by JNDI. But
      we have it only in JMX. So we need to expose it to JNDI.

      In JBoss 5 documentation there is a chapter concerning Cache JNDI exposure, but it says that at the
      time of writing of this document, this functionality is not yet implemented...
      Standard <jndi-name> tag does not work - parser will not read it.
      There is a solution explained in:
      http://www.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/4.2.0.cp06/html/Tree_Cache_Guide/Running_JBoss_Cache_within_JBoss_Application_Server.html
      It gets the cache from JMX and exposes it to JNDI.

      But Hibernate will not accept it, because the exposed interface is CacheJmxWrapperMBean and not
      Cache itself! For our Admin code it is OK, but for Hibernate it's not. It would not accept the exposed bean.

      The question is: is there a way to expose the Cache itself to JNDI, to make Hibernate accept it and also get it for Admin?

      Currently SharedJBossCacheRegionFactory is used and a local instance of Cache is created. It is not exposed to JMX, so we do not have access to it from within the code.

      This is the treecache.xml:
      <?xml version="1.0" encoding="UTF-8"?>
      
      <!-- ===================================================================== -->
      <!-- -->
      <!-- TreeCache Service Configuration for LAMS -->
      
      <!-- This approach is deprecated for JBoss 5 and it is used only temporarly,
       until a way to utilise lams-cache-jboss-beans.xml is found.
       The Cache configured in this file is NOT deployed as a separate service,
       but it is used by Hibernate to create a local (not JMX exposed) instance
       for its own use)
      -->
      <!-- ===================================================================== -->
      
      <server>
      
       <!-- ==================================================================== -->
       <!-- Defines TreeCache configuration -->
       <!-- ==================================================================== -->
      
       <mbean code="org.jboss.cache.TreeCache"
       name="jboss.cache:service=TreeCache">
      
       <depends>jboss:service=Naming</depends>
       <depends>jboss:service=TransactionManager</depends>
      
      
       <!-- Configure the TransactionManager -->
       <attribute name="TransactionManagerLookupClass">org.jboss.cache.transaction.JBossTransactionManagerLookup</attribute>
      
      
       <!--
       Node locking level : SERIALIZABLE
       REPEATABLE_READ (default)
       READ_COMMITTED
       READ_UNCOMMITTED
       NONE
       -->
       <attribute name="IsolationLevel">READ_COMMITTED</attribute>
      
       <!--
       Valid modes are LOCAL
       REPL_ASYNC
       REPL_SYNC
       -->
       <attribute name="CacheMode">LOCAL</attribute>
      
       <!-- Name of cluster. Needs to be the same for all clusters, in order
       to find each other
       -->
       <attribute name="ClusterName">TreeCache-Cluster</attribute>
      
       <!-- JGroups protocol stack properties. Can also be a URL,
       e.g. file:/home/bela/default.xml
       <attribute name="ClusterProperties"></attribute>
       -->
      
       <attribute name="ClusterConfig">
       <config>
       <!-- UDP: if you have a multihomed machine,
       set the bind_addr attribute to the appropriate NIC IP address -->
       <!-- UDP: On Windows machines, because of the media sense feature
       being broken with multicast (even after disabling media sense)
       set the loopback attribute to true -->
       <UDP mcast_addr="228.1.2.3" mcast_port="48866"
       ip_ttl="64" ip_mcast="true"
       mcast_send_buf_size="150000" mcast_recv_buf_size="80000"
       ucast_send_buf_size="150000" ucast_recv_buf_size="80000"
       loopback="false"/>
       <PING timeout="2000" num_initial_members="3"
       up_thread="false" down_thread="false"/>
       <MERGE2 min_interval="10000" max_interval="20000"/>
       <FD shun="true" up_thread="true" down_thread="true"/>
       <VERIFY_SUSPECT timeout="1500"
       up_thread="false" down_thread="false"/>
       <pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
       max_xmit_size="8192" up_thread="false" down_thread="false"/>
       <UNICAST timeout="600,1200,2400" window_size="100" min_threshold="10"
       down_thread="false"/>
       <pbcast.STABLE desired_avg_gossip="20000"
       up_thread="false" down_thread="false"/>
       <FRAG frag_size="8192"
       down_thread="false" up_thread="false"/>
       <pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
       shun="true" print_local_addr="true"/>
       <pbcast.STATE_TRANSFER up_thread="false" down_thread="false"/>
       </config>
       </attribute>
      
      
       <!--
       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
       -->
       <attribute name="InitialStateRetrievalTimeout">5000</attribute>
      
       <!--
       Number of milliseconds to wait until all responses for a
       synchronous call have been received.
       -->
       <attribute name="SyncReplTimeout">10000</attribute>
      
       <!-- Max number of milliseconds to wait for a lock acquisition -->
       <attribute name="LockAcquisitionTimeout">15000</attribute>
      
       <attribute name="EvictionPolicyConfig">
       <config>
       <attribute name="wakeUpIntervalSeconds">5</attribute>
       <!-- Name of the DEFAULT eviction policy class. -->
       <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
       <!-- Cache wide default -->
       <region name="/_default_">
       <attribute name="maxNodes">5000</attribute>
       <attribute name="timeToLiveSeconds">1000</attribute>
       </region>
       <region name="/org/lamsfoundation/lams/contentrepository">
       <attribute name="maxNodes">200</attribute>
       <attribute name="timeToLiveSeconds">900</attribute>
       </region>
       </config>
       </attribute>
       </mbean>
      </server>


      Thank you for your quick reply!
      Marcin Cieslak