Caching and Clustering

This howto will guide you to use the EJB3 cartridge caching and clustering facilities, based on the JBoss distributed/clustered caching environment.

JBoss Cache supports a high performance, in-memory, transactional, and replicated cache for the cluster.

JBoss Cache has 2 types of caching

  • Entity Cache - caching database objects like entity POJOs and query results.
    • POJOs are cached in-memory.
    • Reduces round trips to the database server.
    • Access by one node in the cluster makes the POJO available to all nodes via the distributed entity cache.

  • State Cache - stores application state information.
    • HTTP session state can be cached and accessed across all nodes.
    • Caching includes stateful session beans.
    • Can cache transient properties across nodes.

The following example was taken from the manageable entities howto with the caching options enabled. The manageable components are not relevant here and will not be discussed.

images/org/andromda/test/17/a/uml.gif

  • Auto-generated source that does not need manual editing
  • Auto-generated source that should be edited manually
  • File that is affected by the modifications applied in this section

Remember: You must set the persistenceProviderExtensions namespace property such that Hibernate cache specific annotations are generated.

The following sections will show you how to enable and configure caching and clustering.

Cache Configuration

The EJB3 cartridge allows you to configure caching through namespace properties via your application andromda.xml descriptor. Make sure the hibernateCacheProvider and hibernateTreecacheMbeanObject properties are defined to use the internal JBoss Cache with JBoss.

        <namespace name="ejb3">
            <properties>
                ...
                <property name="hibernateCacheProvider">org.jboss.ejb3.entity.TreeCacheProviderHook</property>
                <property name="hibernateTreecacheMbeanObject">jboss.cache:service=EJB3EntityTreeCache</property>
                <!-- uncomment to enable default entity cache settings -->
                <property name="hibernateEntityCache">TRANSACTIONAL</property>
                <!-- uncomment to enable default association caching configuration -->
                <property name="hibernateAssociationCache">TRANSACTIONAL</property>
                ...
            </properties>
        </namespace>
The hibernateEntityCache and hibernateAssociationCache properties define the default cache settings if you choose to enable entity and association caching.

Your generated persistence.xml descriptor will look something like:

<?xml version="1.0" encoding="UTF-8"?>
<!--
     Attention: Generated code! Do not modify by hand!
     Generated by: persistence.xml.vsl in andromda-ejb3-cartridge.
  -->
<persistence>
    <persistence-unit name="howtomodelcaching">
        <jta-data-source>java:/jdbc/howtomodelcaching</jta-data-source>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"/>
            <property name="hibernate.cache.provider_class" value="org.jboss.ejb3.entity.TreeCacheProviderHook"/>
            <property name="hibernate.treecache.mbean.object_name" value="jboss.cache:service=EJB3EntityTreeCache"/>
        </properties>
    </persistence-unit>
</persistence>

Entity Cache

In situations where data, persisted by entity beans are rarely changed, you can employ the entity cache option to avoid unnecessary round-trips to the database.

To enable entity caching, you enable the hibernateEnableCache ejb3 namespace property in your andromda.xml like so:

        <namespace name="ejb3">
            <properties>
                ...
                <property name="hibernateEnableCache">true</property>
                <property name="useDefaultCacheRegion">false</property>
                ...
            </properties>
        </namespace>
This property must be enabled before all other caching properties are fine-tuned.

The useDefaultCacheRegion property allows you to specify whether you want all entities to use the default cache region specified in ejb3-entity-cache-service.xml and the cache region set on corresponding finder queries. By default, this is set to false. If you set it to true, the user specified cache regions for entities will not be defined.

If you enable the default entity caching in your andromda.xml descriptor (by enabling hibernateEntityCache), then caching will be enabled for all entities. To override this default value, you can model the andromda_persistence_entity_cache tagged value on individual entities.

Once you have enabled entity caching, you will notice the @org.hibernate.annotations.Cache annotation at the class level in all entities.

The corresponding entity cache region is defined in the ejb3-entity-cache-service.xml configuration service file for the Car and Person entities:

        ....
        <!-- The Car entity cache -->
        <region name="/org/andromda/howto2/rental/Car">
          <attribute name="maxNodes">10000</attribute>
          <attribute name="timeToLiveSeconds">5000</attribute>
        </region>

        <!-- The Person entity cache -->
        <region name="/org/andromda/howto2/rental/Person">
          <attribute name="maxNodes">10000</attribute>
          <attribute name="timeToLiveSeconds">5000</attribute>
        </region>
        ....

You must deploy the ejb3-entity-cache-service.xml to your JBoss deploy folder as you do with your ear package bundle. Remember, if you have other cached enabled applications, you must merge the changes to the ejb3-entity-cache-service.xml manually, otherwise you will override previous configurations.

Association Cache

To enable entity association relationship caching, you enable the hibernateEnableAssociationsCache ejb3 namespace property in your andromda.xml like so:

        <namespace name="ejb3">
            <properties>
                ...
                <property name="hibernateEnableCache">true</property>
                <property name="hibernateEnableAssociationsCache">true</property>
                ...
            </properties>
        </namespace>
You must have hibernateEnableCache enabled.

If you enable the default association cache strategy in your andromda.xml descriptor, (by enabling hibernateAssociationCache), then all collection association caching will be enabled by default. To override this default value, you can model the andromda_persistence_association_cache tagged value on individual target association ends.

Once you have enabled entity association caching, you will notice the @org.hibernate.annotations.Cache annotation on One-To-Many and Many-To-Many relationships.

Query Cache

To enable entity query caching for all queries, you enable the hibernateUseQueryCache ejb3 namespace property in your andromda.xml like so:

        <namespace name="ejb3">
            <properties>
                ...
                <property name="hibernateEnableCache">true</property>
                <property name="hibernateUseQueryCache">true</property>
                <property name="useDefaultCacheRegion">false</property>
                ...
            </properties>
        </namespace>
You must have hibernateEnableCache enabled. This will enable the query cache for all queries, including your generic query, the findAll query.

In many circumstance, you shouldn't enable query cache for all queries (using the hibernateUseQueryCache property) but enable caching for required queries only. You can enable caching for individual finder method using the andromda_ejb_query_useCache tagged value which is modeled on the finder method.

The useDefaultCacheRegion property allows you to specify whether you want all queries to use the default cache region specified in ejb3-entity-cache-service.xml. By default, this is set to false. If you set it to true, the user specified cache regions will not be defined and the hint on queries to set the cache region will not be assigned.

The cartridge will look for at least one query which is marked for caching. If it finds one such query, the persistence.xml descriptor will include the hibernate.cache.use_query_cache like so:

<?xml version="1.0" encoding="UTF-8"?>
<!--
     Attention: Generated code! Do not modify by hand!
     Generated by: persistence.xml.vsl in andromda-ejb3-cartridge.
  -->
<persistence>
    <persistence-unit name="howtomodel2">
        <jta-data-source>java:/jdbc/howtomodel2</jta-data-source>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"/>
            <property name="hibernate.cache.provider_class" value="org.jboss.ejb3.entity.TreeCacheProviderHook"/>
            <property name="hibernate.treecache.mbean.object_name" value="jboss.cache:service=EJB3EntityTreeCache"/>
            <property name="hibernate.cache.use_query_cache">true</property>
        </properties>
    </persistence-unit>

In the above example, the Car entity has the findByType finder marked as cacheable. When generating thefindByType DAO method in CarDaoBase.java, the cartridge will set the org.hibernate.cacheRegion hint automatically like so:

public java.util.List findByType(final int transform, final org.andromda.howto2.rental.CarType type)
    throws org.andromda.howto2.rental.CarDaoException
{
    try
    {
        javax.persistence.Query queryObject = emanager.createNamedQuery("Car.findByType");
        queryObject.setParameter("type", type.name());
        queryObject.setHint("org.hibernate.cacheRegion", "/org/andromda/howto2/rental/Car_findByType");
        java.util.List results = queryObject.getResultList();
        transformEntities(transform, results);
        return results;
    }
    catch (Exception ex)
    {
        throw new org.andromda.howto2.rental.CarDaoException(ex);
    }
}

The corresponding cache region is defined in the ejb3-entity-cache-service.xml configuration service file:

        ....
        <!-- The Car entity cache -->
        <region name="/org/andromda/howto2/rental/Car">
          <attribute name="maxNodes">10000</attribute>
          <attribute name="timeToLiveSeconds">5000</attribute>
        </region>
        ....

You must deploy the ejb3-entity-cache-service.xml to your JBoss deploy folder as you do with your ear package bundle. Remember, if you have other cached enabled applications, you must merge the changes to the ejb3-entity-cache-service.xml manually, otherwise you will override previous configurations.

Clustering Session Beans

Enabling session bean clustering is achieved by setting the enableClustering ejb3 namespace property to true.

        <namespace name="ejb3">
            <properties>
                ...
                property name="enableClustering">true</property>
                ...
            </properties>
        </namespace>
This will automatically add the @org.jboss.annotation.ejb.Clustered JBoss annotation to all session beans which will enable load-balancing and failover of all requests (if you have configured clustering on the container). The default load balance policy org.jboss.ha.framework.interfaces.RandomRobin is used.

There is nothing more you need to do for stateless session beans. For stateful session beans, you must make sure that the JBoss Cache session state replication service is deployed. Simply make sure that ejb3-clustered-sfsbcache-service.xml exists in your JBoss deploy directory.

Further Reading

Visit the following links to find out more information

  • http://clusterstore.demo.jboss.com/
  • http://docs.jboss.org/ejb3/app-server/tutorial/clusteredentity/clusteredentity.html

Next

To expose service operations and session beans as webservices click here.