Thursday, May 29, 2008

REST 0.7, now with Spring support

REST 0.7 is out and now includes support for the Spring framework. Peter Liu has written a nice example that uses NetBeans 6.1 to create a web application that contains a Spring-aware servlet, a singleton resource, and a request resource. His example is derived from a blog post by Paul Sandoz showing how to manually integrate Spring and Jersey (and predating REST 0.7).

Note that in REST 0.8, Spring support will be enhanced so that the user does not have to create a Spring-aware servlet.

This is Peter's example. It requires NetBeans IDE Web and Java EE distribution 6.1 and REST plugin 0.7.

  1. Create a Web Application project and name it SpringRestWebApp. On the Frameworks page of the project creation wizard, select Spring Web MVC 2.5.
  2. Right-click the SpringRestWebApp node and choose New > RESTful Web Services from Patterns. Select the Singleton pattern and name the resource Singleton (class name will then be SingletonResource). Create the test.servlet package to contain the resource.
  3. Replace the code in SingletonResource with the following. Right-click in the code and select Fix Imports after replacing the code.
    @Path("singleton")
    @Singleton
    public class SingletonResource {
        
        private String name;
        
        private int uses = 0;
        
        private synchronized int getCount() {
            return ++uses;
        }
        
        public SingletonResource() {
            name = "unset";
        }
    
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }
        
        @GET
        @ProduceMime("text/plain")
        public String getDescription() {
            return "Name: " + getName() + ", Uses: " + Integer.toString(getCount());
        }
    }
  4. Create another RESTful Web Service using the Singleton pattern. Name the resource PerRequest and create it in the same test.servlet package.
  5. Replace the code in PerRequestResource with the following. Right-click in the code and select Fix Imports when you are done.
    @Path("request")
    public class PerRequestResource {
        
        private String name;
        
        private int uses = 0;
        
        private synchronized int getCount() {
            return ++uses;
        }
        
        public PerRequestResource() {
            name = "unset";
        }
    
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }
        
        @GET
        @ProduceMime("text/plain")
        public String getDescription() {
            return "Name: " + getName() + ", Uses: " + Integer.toString(getCount());
        }
    }
  6. Right-click the SpringRestWebApp node and choose New > Servlet. Name the servlet SpringServlet and create it in the test.servlet package.
  7. Replace the code in SpringServlet with the following. Right-click in the code and select Fix Imports when done.
    public class SpringServlet extends ServletContainer {
        
        private static class SpringComponentProvider implements ComponentProvider {
            private ApplicationContext springContext;
    
            SpringComponentProvider(ApplicationContext springContext) {
                this.springContext = springContext;
            }
            
            private String getBeanName(Class c) {
                String names[] = springContext.getBeanNamesForType(c);
                if (names.length == 0) {
                    return null;
                } else if (names.length > 1) {
                    throw new RuntimeException("Multiple configured beans for " 
                            + c.getName());
                }
                return names[0];            
            }
            
            public Object getInstance(Scope scope, Class c) 
                    throws InstantiationException, IllegalAccessException {            
                String beanName = getBeanName(c);
                if (beanName == null) return null;
                
                if (scope == Scope.WebApplication && 
                        springContext.isSingleton(beanName)) { 
                    return springContext.getBean(beanName, c);
                } else if (scope == Scope.ApplicationDefined &&
                        springContext.isPrototype(beanName) &&
                        !springContext.isSingleton(beanName)) {
                    return springContext.getBean(beanName, c);
                } else {
                    return null;
                }
            }
    
            public Object getInstance(Scope scope, Constructor contructor, 
                    Object[] parameters) 
                    throws InstantiationException, IllegalArgumentException, 
                    IllegalAccessException, InvocationTargetException {
                return null;
            }
    
            public Object getInjectableInstance(Object instance) {
               return instance;
            }
            
            public void inject(Object instance) {
            }        
        };
        
        @Override
        protected void initiate(ResourceConfig rc, WebApplication wa) {
            ApplicationContext springContext = WebApplicationContextUtils.
                    getRequiredWebApplicationContext(getServletContext());
            
            wa.initiate(rc, new SpringComponentProvider(springContext));
        }        
    }

    Paul Sandoz writes "Notice that SpringServlet extends ServletContainer and the initiate method is overridden. This method creates an ApplicationContext and then initiates the WebApplication by passing in an instance of the static inner class SpringComponentProvider. This class implements ComponentProvider and the getInstance method will attempt to obtain a Spring bean that is present and matches the requested scope, if so then the bean instance is returned otherwise null is returned. (Note that the getInstance method with a Constructor type parameter is not implemented, this is because we have not determined how to support constructors with Spring beans)."

  8. Open the project's web.xml file. Replace com.sun.ws.rest.impl.container.servlet.ServletAdaptor with test.servlet.SpringServlet.
  9. Add the following to the project's applicationContext.xml file, to initialize the resources:
    <bean id="bean1" scope="singleton" class="test.servlet.SingletonResource">
         <property name="name" value="Mr. Singleton Bean"/>
    </bean>
    <bean id="bean2" scope="prototype" class="test.servlet.PerRequestResource">
         <property name="name" value="Mr. PerRequest Bean"/>
    </bean>
  10. Right-click the project node and select Test RESTful Web Services.

When you test the Singleton path, the service returns the Mr. Singleton Bean property and the Uses value increments for every request. When you test the PerRequest path, the service returns the Mr. PerRequest Bean property and the Uses value does not increment.

by: Jeffrey Rubinoff

Monday, May 26, 2008

Lessons Learned From Spring’s @Autowired

Last November we got Spring 2.5 and with it the possibility to use annotations for dependency injection (DI). Annotations can be used instead or mixed with the classic application context file(s) based on XML.

If you compare the former more complex XML configurations with what you still have to keep, after using annotations, it’s quite amazing how straightforward the XML becomes. For projects with complex DI configurations it is possible to transfer the configuration in steps.

For our ICEfaces Web application e.g. we started with something like this:

<bean id="businessObject"
    class="com.test.BusinessObject"
    scope="session">
    <aop :scoped-proxy/>
    <property name="simpleProperty">
        <value>Hello World</value>
    </property>
</bean>

<bean id="businessObjectAdministration"
    class="com.test.BusinessObjectAdministration"
    scope="session">
    <aop :scoped-proxy/>
    <property name="simpleProperty">
        <value>Hello Administrators</value>
    </property>
</bean>

<bean id="backingBean"
    class="com.test.BackingBean" scope="session">
    <aop :scoped-proxy/>
        <property name="businessObject">
            <ref bean="businessObject" />
        </property>
</bean>

<bean id="backingBeanAdministration"
    class="com.test.BackingBeanAdministration"
    scope="session">
    <aop :scoped-proxy/>
        <property name="businessObjectAdministration">
            <ref bean="businessObjectAdministration" />
        </property>
</bean>

This is pretty verbose. The references can also be written in compact syntax, like this:

<property name="businessObject" ref="businessObject" />

Here are the corresponding classes:

package com.test;
public class BusinessObject {

    String simpleProperty;

    public void setSimpleProperty(String simpleProperty) {
        this.simpleProperty = simpleProperty;
    }
    public String getSimpleProperty() {
        return this.simpleProperty;
    }
}

package com.test;
public class BusinessObjectAdministration extends
    BusinessObject {

}

package com.test;
public class BackingBean {

    BusinessObject businessObject;

    public void setBusinessObject(BusinessObject businessObject) {
        this.businessObject = businessObject;
    }
    public String getBusinessObject() {
        return this.businessObject;
    }
}

package com.test;
public class BackingBeanAdministration {

    BusinessObjectAdministration businessObjectAdministration;

    public void setBusinessObjectAdministration(
        BusinessObjectAdministration businessObjectAdministration) {
        this.businessObjectAdministration = businessObjectAdministration;
    }
    public String getBusinessObjectAdministration() {
        return this.businessObjectAdministration;
    }
}

Each backing bean in this example uses a corresponding business object, whereas BusinessObjectAdministration is a child of BusinessObject.

Adding Annotations

So, what do we have to change to get this annotation stuff working? The reference attributes in the backing beans get an @Autowired. With this a corresponding Spring bean with the same type is searched during the dependency injection. Additionally, we can skip getter and setter for the reference attributes.

public class BackingBean {

    @Autowired
    BusinessObject businessObject;

    ...
}

public class BackingBeanAdministration {

    @Autowired
    BusinessObjectAdministration businessObjectAdministration;

    ...
}

With this we can also skip the corresponding properties in the application context:

<bean id="backingBean"
    class="com.test.BackingBean" scope="session">
    <aop :scoped-proxy/>
</bean>

<bean id="backingBeanAdministration"
    class="com.test.BackingBeanAdministration"
    scope="session">
    <aop :scoped-proxy/>
</bean>

Pretty simple. But, when you deploy this you get an exception. Spring will tell you that it has problems to inject the businessObject reference into backingBean.BusinessObject, because there are two matches. We’ve an inheritance between BusinessObject and BusinessObjectAdministration. So, both are matched in this case.

Matching via type is not the best solution here. But, there’s another annotation that allows to name the Spring bean we wanna be used during the dependency injection, called @Qualifier. It has a parameter, that allows to set the bean’s name.

When we add this to the backing beans everything works fine.

public class BackingBean {

    @Autowired
    @Qualifier("businessObject")
    BusinessObject businessObject;

    ...
}

public class BackingBeanAdministration {

    @Autowired
    @Qualifier("businessObjectAdministration")
    BusinessObjectAdministration businessObjectAdministration;

    ...
}

Sunday, May 25, 2008

SpringSource Application Platform

So, Spring Source has been able to keep a secret from us :-) Secretly, they have been developing what looks a lot like a new application server, not like the JEE market, but with the springframework at its core. A well kept secret, which I did not see coming, even though we might have been able to, given the portfolio of products and people now employed at Spring Source.

And what are we to say to that? Me, personally, I welcome it. Yeah yeah, it is a non-standard, proprietary way to go, when compared to JEE servers. But, I am already utilizing the springframework as my main engine and have long time gone the POJO ORM way. All this way before JEE5 and JPA. And I like it. I have even ditched using JEE5 EJBs on new products, because I find the spring model superior in many ways.

And about it being proprietary. The platform is GPLv3 licensed, which I really like. In my eyes, the GPL license model is good for exactly this kind of product. It ensures openness, also when utilized by others, which adds or enhances it. We will have to give our contributions back! And that is good, for something that acts as a platform. Just like the Linux kernel, actually.

What Is It?

At a first glance, it looked to me as a lot like a server like the JBoss micro kernel architecture, which could (can) be tailored to only run the exact parts of JEE, that your application needs. No need to start JMS servers and EJB containers, if you ain’t gonna need it. I never got to like JBoss, though.

At a second glance, this is actually just a minor part of the Spring Source Application Platform (as I see the benefits to me). They are using OSGi (through a Spring Dynamic Modules kernel), to control their “services when needed” in the server, but they are also using it (OSGi) as the technology for deployment units for the applications running on it. Our applications! And that is where I see some benefits for me, as an application developer.

What Is the OSGi Part All About?

SpringSource consider war-deployment as not good enough and suggests the use of OSGi as deployment modules instead. I agree, that this might be a good choice, I just hope it will be simple enough to use. I do not agree totally, on the points of Rod Johnson here, where he states this about war deployment:

…the great deal of duplication going on with web.xml files, Spring configuration file, and so on. Also, the Java EE web-inf folder is unversioned and messy. It has problems with dependencies and potential duplications…

The war deployment unit (web.xml) is nice and simple. I for one, don’t mind putting the configuration data in there. Actually, I recently saw, that the expert group on the next servlet spec are working on features to make this easier. They are talking about auto-discovery of configuration data from web frameworks, so the need to edit web.xml becomes minor or vanishes.

What I like about the OSGi way of deployment, is the tight control on dependencies, that your can utilize. One example is how you tightly control which packages, a given (deployed) component, exports to other deployed components. I hope to see this solve the jar dependencies hell. Something that upcoming Java versions, JSR-294 and JSR-277 is also seeking to solve, albeit with a far too long time frame. OSGi is here today and works.

What’s more is, that OSGi is not only used to implement the micro kernel in the Spring DM kernel, but is also exposed to us developers, to use when deploying. I have recently battled an issue with hibernate using cglib and an old asm library, while at the same time needing CXF 2.1 which in turn needs asm lib 2.x. The problem was, that the two asm lib versions where binary incompatible. This can be solved elegantly with OSGi, by deploying each part of the application as separately packages groups, and not exposing the asm libs from these modules. Each group can then have their own asm library jar. Something which we, today, are trying to solve by re-packaging libraries under other package names, using tools like JarJar Links.

Everyday Development

So, what does working with Spring Source Application Platform actually mean to us developers then, in our daily work?

The Server

Well, I like the idea of a spring-powered environment, where the need for configuration is far less. I hope it will be as easy as it is to start with EJB3, but with the power to extend with all the extra “magic”. I think JEE5 has had one good thing going for it, and that is it being easier to get started with. No need to know about and correctly configure the spring bean context.

The Need for OSGi Bundles

The libraries that our application depends upon, such as hibernate, spring, commons, etc., must be available as an OSGi bundle or library. This is the way of expressing dependencies in SpringSource Application Platform. What did we do before? Well, most of us just expressed our dependencies in the maven POM and let it (maven) download the proper jars from a maven repository. The maven repository has grown up to be very important, hence just about all java libraries are published in it. But not as OSGi bundles.

To address the need for OSGi packaged versions of libraries , SpringSource has made available their own repository of OSGi bundles here. Naturally, this repository is only a fraction of what is in the maven repository, and this will be a nuisance in the beginning. Frankly, I can only see that nuisance going away, if the SpringSource Application Platform becomes world popular, as they (SpringSource) will need community contributions from framework/lib developers themselves, to keep up with the steady flow of new versions.

Maybe the maven repository should be extended, to include such bundles. It seems to be the packaging of tomorrow. Not just because of OSGi becoming more and more popular and the Spring Source Application Platform, but also because of the upcoming work on modularity in the Java platform.

Sun “Answering”

I do not know, if it is stuff like SpringSource Application Platform, that is pushing JSR-294 and JSR-277 to “merge”. It is a fact, that the springframework, together with powerfull POJO ORM frameworks, have threatened the JEE world heavily the last couple of years. Sun has had work on modularity going on for quite some time now (in JSR-294 and JSR-277), but it has also received a lot of heat. Mostly for not leaning to just accept the existing de-facto standard, OSGi, and go with that. Well, it seems they (Sun) might be shaping up. Stanley Ho, spec lead of JSR-277, announces that Alex Buckley (the spec lead on the other JSR on modularity, JSR-294) will join JSR-277 and bring the language level module specs into that JSR group.

All good stuff.

OSGi and Spring

It’s time to move on and show the simple elegance Spring brings to OSGi development using the HelloWorldSpec sample from the OSGi & Modularity post. But first, a little primer on Spring Dynamic Modules. Spring DM is not an OSGi implementation. Instead, Spring DM aims to make working with OSGi easier just as Spring makes the world of Enterprise Java simpler. One of the more striking characteristics of Spring DM is that it removes most your code’s dependencies on OSGi by taking care of the OSGi plumbing. To function in an OSGi runtime environment, the Spring .jars have been packaged as OSGi bundles.

The easiest way to show this is by expanding on the HelloWorldSpec sample from my previous post. Reviewing the HelloConsumer and HelloServiceImpl classes reveal that each are rather tightly coupled to the OSGi API. As we’ll soon see, using Spring removes those dependencies, making the Spring edition of HelloConsumer and HelloServiceImpl simple POJOs. Of course, the dependency on OSGi has to live somewhere, and for those familiar with Spring, we know it lives in the Spring configuration files.

The Spring DM configuration files live in a META-INF/Spring directory, which you can see in my Google Code Repository for the HelloWorldSpecSpring project. There are two files, and each are described below:

It isn’t necessary to separate the configuration into two separate files. However, experienced Spring users typically separate configuration elements to making management and testing easier. In this case, the two configuration files allows me to test the helloService bean outside of the OSGi runtime.

Since Spring is now managing the service within the Felix runtime, I have to install the necessary Spring bundles to Felix. As with the other examples, I’ve done this for you within the HelloWorldSpecSpring project. Of course, when starting Felix, you can always create a new profile by entering a different profile name and install the bundles yourself. The bundles within the SpringLib directory are those I found were required to ensure the Spring DM modules resolvd correctly. If you do choose to create your own profile, it’s likely you’ll have to modify the config.properties file to point to the location of your Felix runtime, which means you’ll have to download Felix to get these bundles since I only include the Felix runtime in the HelloWorldSpecSpring distribution, not the bundles. You won’t have to do this if you use the HelloWorldSpecSpring profile because the bundles have already been installed.

After installing the client.jar and service.jar, I should be able to perform the execute same start, stop, and install sequence described in my earlier post on OSGi & Modularity, and receive the exact same results. Except this time, Spring is managing the dependencies on the OSGi API and my classes remain simple POJOs. Spring’s simple elegance helping yield a higher quality design with fewer dependencies on the OSGi API.

by Kirk Knoernschild

Saturday, May 10, 2008

Presenting the version number on a web front end with spring and maven

This entry will describe how to present a application version number in the pom.xml on a web front end by using spring and maven. Maven generates by default a pom.properties file in the META-INF folder when generating a war. This file holds the following fields; version, groupId, artifactId
The exact location from your context root is;

META-INF/maven/<groupId>/<artifactId>/pom.properties

by specifying the following bean in your spring config; (REPLACE <groupId> and <artifactId> with what you have defined in your pom.xml)
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>META-INF/maven/<groupId>/<artifactId>/pom</value>
</list>
</property>
</bean>

Now the properties in this file can be used in your font-end by using
the standard spring tags for example to print the version number in a
jsp file use the following line;
<b>Version:</b> <spring:message code="version"/>

REMARK don't forget to add the spring tag definition to your jsp file;
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>

Thursday, May 8, 2008

Pragmatic Caching - a simple Cache Configuration Model for Spring

Caching is a widely used instrument when it comes to performance tuning a given application (of course not until you’ve measured the real bottlenecks). For example, you may want to cache objects that are expensive to fetch (i.e. an object graph from database) or to calculate. Whereas most of us have used a kind of Map to ‘cache’ some data on ad hoc basis in the past, there are a couple of mature caching solutions at the market in the meantime that offer sophisticated features for caching, which goes beyond simply holding objects in memory (e.g. Thread pool controls, Element grouping, Remote server chaining (or clustering), failover, …) Deciding to use such a cache solution always comes with the question of the resulting complexity impact when applying ‘cache logic’ to your application.

Caching is an Aspect

One could rightly say, that caching is a cross cutting concern, that shouldn’t be intermingled with the rest of your business or application logic. Especially the Spring framework provides different options to cope with cross cutting concerns. Spring Modules - a sub project of the Spring framework - offers Support for declarative caching that uses Springs AOP capabilities. It provides a generic ‘API’ while supporting a bunch of different cache solutions (e.g. EHCache, JCS, OSCache, GigaSpaces, …) under the hood.

Pragmatic Caching

While its very easy to declare caching models (resp. flushing models) in a declarative (and more abstract) style with Spring Modules Caching, you sometimes may want to do it in a more programatic way due to some specific caching behaviour that’s difficult to reflect by using generic, declarative expressions. For example you may want to build a more complex cache key or decide which object to cache due to runtime conditions. In this case it may be better (and simpler) to handle caching in a more programmatic way, still treating caching as a cross cutting concern. The following solution is by far not comparable with Spring Modules Caching, yet provides a slightly different model for declaring and using a Cache. Only the core configuration and instantiation of the Cache will be managed by Spring. Caching and Flushing can be managed programmatically, giving you the full power of expressing ‘caching logic’ by the underlying language.

Pragmatic Desicions

We will use only a particular Cache solution - for example the Java Caching System (JCS), so we don’t have to cope with a variety of different Cache APIs. While Spring Modules Caching have to provide a more abstract API which is able to handle different Cache solutions, focussing on a specific solution allows us to manage cache configuration with far less code (We could of course come up with a similar abstraction of caches which allows us to write Adapters for different Cache solutions - but that’s not in the focus of this post).

Programmatic Interception

The basic concept of AOP (remember - caching is an Aspect) is method interception. In our case we want to intercept calls to service methods that provide expensive to fetch or expensive to calculate objects (and thus separating business or application logic from caching logic).
Interception is done in order to deliver objects that were cached due to prior calls (once delegated to the intercepted service).

Let’s imagine a CustomerDAO interface, which is implemented by
HibernateCustomerDAO. In order to intercept arbitrary calls to HibernateCustomerDAO, we’ll define CustomerDAOCacheInterceptor for which we’ll provide a readily configured Cache instance:

public class CustomerDAOCacheInterceptor implements CustomerDAO{

    private static final String CACHE_GROUP_VIP = "VIP";
    ...

    private JCS customerCache = null;
    private CustomerDAO target = null;

    public void setTarget( CustomerDAO target ){
        this.target = target;
    }

    public void setCustomerCache( JCS cache ){
        this.customerCache = cache;
    }
    ...

    public Customer loadCustomerByLogin( String loginId ) {

        String cacheKey = calculateCacheKey( loginId );
        String cacheGroup = getCacheGroup( loginId );

        Customer customer = (Customer)
        customerCache.getFromGroup( cacheKey, cacheGroup );

        if( customer == null ){
            customer = target.loadCustomerByLogin( loginId );

            if( customer != null ){
                try{
                    customerCache.putInGroup( cacheKey, cacheGroup, customer );
                }
                catch ( CacheException e ){
                    throw new RuntimeException(
                        "exception while trying to store Customer to cache (JCS)", e );
                }
            }
        }
        return customer;
    }

    public void update( Customer customer ) {

        target.update( Customer );

        if( someCondtionsMetOn( customer ) ){
            try{
                invalidateGroup( CACHE_GROUP_VIP );
            catch ( CacheException e ){
                throw new RuntimeException( "exception while invalidating VIP cache (JCS)", e );
            }
        }
    }
    ...
}

As you’ve seen, the Interceptor is provided with a target - the CustomerDAO implementation which is asked for a Customer in case the affected Customer isn’t cached yet (normally our HibernateCustomerDAO).
Further on, a readily configured JCS Cache instance is injected (as said before, we could easily come up a cache abstraction by shielding the Intercepor from the concrete cache instance with an appropriate cache interface), so the Interceptor doesn’t have to cope with Cache configuration and cache creation itself (maybe there are other DAOs that will use the same cache instance, so we have to come up with a central cache configuration and instantiation mechanism anyway).

Let’s say that the cache key is calculated by a more or less complex logic, that’s better described within Java. Same goes for using cache groups within the ‘customer cache’. Handling different cache groups and detecting the right cache group for a certain customer may be better placed inside the Interceptor using the full power of the language (again, the same might be true for determining conditions under which the cache or a certain cache group have to be flushed as shown in method update() ).
Note, that the demonstration doesn’t include logic to handle concurrent access - this ‘exercise’ is left to you since we only want to take a look at the caching logic.

Basic cache configuration

JCS (like most of the other cache solutions) provides a way to configure caches by using a cache configuration file (*.ccf). In it, we’ll describe the different caches which are supposed to be used within our application (for further information, please refer to the documentation):

# DEFAULT CACHE REGION
jcs.default=DC
jcs.default.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=100
jcs.default.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache

# PRE-DEFINED CACHE REGIONS
jcs.region.customerCache=DC
jcs.region.customerCache.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes
jcs.region.customerCache.cacheattributes.MaxObjects=200
jcs.region.customerCache.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache
jcs.region.customerCache.elementattributes.MaxLifeSeconds=2400

jcs.region.priceCache=DC
jcs.region.priceCache.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes
jcs.region.priceCache.cacheattributes.MaxObjects=100
jcs.region.priceCache.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache
jcs.region.priceCache.elementattributes.MaxLifeSeconds=1200

We’ve defined a default configuration and a cache coniguration for our customer cache. We could of course could have defined some more cache regions in order to cache other objects or object categories within our application (e.g. a particular region for caching Articles or calculated Prices).
That’s all we need to start. The last question (and most interesting for this post) is who’s responsible for instantiating and managing the different ‘caches’ (resp. cache regions)?

Say it with a FactoryBean

Within an application context, all we want to do is pointing to the underlying cache configuration file and choose a particular cache region (defined within the cache configuration file) by its name to bring the different cache instances to life.
This is easily done by leveraging a FactoryBean, which is responsible for the creation and management of our caches. By Injecting the path and name of the cache configuration file and the name of the cache region the FactoryBean should deliver the corresponding cache instance.

package org.common.cache;

import java.util.HashMap;
import java.util.Map;

import org.apache.jcs.JCS;
import org.apache.jcs.access.exception.CacheException;
import org.springframework.beans.factory.FactoryBean;

public class JCSCacheFactoryBean implements FactoryBean {

    private Map<String,JCS> caches = new HashMap<String,JCS>();

    private String configLocation = null;
    private String region = null;

    public void setConfigLocation(String configLocation) {
        this.configLocation = configLocation;
    }

    public void setRegion(String region) {
        this.region = region;
    }    

    public Object getObject() throws Exception {
        try{
            String cacheRegionKey =
                new StringBuffer( configLocation )
                    .append( "." ).append( "region" ).toString();

            JCS cache = null;

            if( caches.containsKey( cacheRegionKey ) ){
                cache = caches.get( cacheRegionKey );
            }
            else{
                JCS.setConfigFilename( configLocation );
                cache = JCS.getInstance( region );
                caches.put( cacheRegionKey, cache );
            }

            return cache;
        }
        catch ( CacheException e ){
            throw new RuntimeException( "exception while initializing cache (JCS)", e );
        }
    }

    public Class getObjectType() {
        return JCS.class;
    }

    public boolean isSingleton() {
        return true;
    }
}

As you’ve seen, the implementation is very straightforward. Every time a cache instance is requested, the FactoryBean will look for an appropriate cache which is already created and in memory or is creating a new instance according to the current property values configLocation and region.

A cache bean

With the given FactoryBean, it’s easy to define a ‘cache bean’ simply by providing the cache configuration file and the name of a defined cache region.
Now you can wire up dependend beans (e.g. CustomerDAOInterceptor) simply by injecting the cache bean.

    <bean id="customerDAO" class="org.sample.intercept.<span><span>CustomerDAOCacheInterceptor</span></span>">
        <property name="target">
            <bean class="org.sample.CustomerDAO">
                <property name="sessionFactory"><ref local="hibernateSessionFactory"/></property>
            </bean>
        </property>
        <property name="customerCache"><ref bean="customerCache"/></property>
    </bean>

    <bean id="customerCache" class="org.sample.cache.JCSCacheFactoryBean">
        <property name="configLocation"><value>/cache.ccf</value></property>
        <property name="region"><value>customerCache</value></property>
    </bean>

    <bean id="priceCache" class="org.sample.cache.JCSCacheFactoryBean">
        <property name="configLocation"><value>/cache.ccf</value></property>
        <property name="region"><value>priceCache</value></property>
    </bean>
    ....

It’s of course possible to wire up more than one bean with a needed cache bean just as well as you can define arbitrary cache beans which represent different cache regions.

Summary

We’ve come up with a very pragmatic solution with a declarative style for cache configuration and a more programmatic style for handling caching behaviour. As always, the usefulness of such a solution depends on the given problem space and the surrounding forces.
While Spring Modules Caching allows for a more generic style for all aspects of cache confiuration and cache processing (with less code to write!) the given solution is only half-declarative (only for the configuration part) providing more power in expressing the cache processing part.

As always, its a kind of trade off - you’ll have to choose the right tool for the right situation …

by Mario Gleichmann