/* * Created on Oct 22, 2004 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * Copyright @2004 the original author or authors. */ package org.springmodules.cache.integration; import java.io.Serializable; import java.util.List; import junit.framework.TestCase; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.util.StringUtils; import org.springmodules.cache.integration.KeyAndModelListCachingListener.KeyAndModel; import org.springmodules.cache.interceptor.caching.AbstractCachingInterceptor; import org.springmodules.cache.provider.PathUtils; import org.springmodules.cache.util.SystemUtils; /** * <p> * Template for test cases that verify that caching module works correctly * inside a Spring bean context. * </p> * * @author Alex Ruiz * * @version $Revision$ $Date$ */ public abstract class AbstractIntegrationTests extends TestCase { protected static final String CACHE_MANAGER_BEAN_NAME = "cacheManager"; private static final String ANNOTATIONS_CONTEXT = "annotationsContext.xml"; private static final String BEAN_NAME_AUTOPROXY_CREATOR_CONTEXT = "beanNameAutoproxyCreatorContext.xml"; private static final String CACHE_PROXY_FACTORY_BEAN_CONTEXT = "cacheProxyFactoryBeanContext.xml"; private static final String COMMONS_ATTRIBUTES_CONTEXT = "commonsAttributesContext.xml"; private static final String DTD_FOLDER = "/dtd/"; private static final String SCHEMA_FOLDER = "/schema/"; protected final Log logger = LogFactory.getLog(getClass()); private ApplicationContext applicationContext; /** * Listener that stores the keys used to store objects in the cache. This * listener is used to verify that objects are being cached. */ private KeyAndModelListCachingListener cachingListener; /** * Bean managed by the Spring bean context. Should be advised by the * interceptors that perform caching and flush the cache. */ private CacheableService target; public AbstractIntegrationTests() { super(); } public AbstractIntegrationTests(String name) { super(name); } public final void testAnnotationsWithDtd() throws Exception { performCachingAndFlushingWithAnnotations(DTD_FOLDER); } public final void testAnnotationsWithSchema() throws Exception { performCachingAndFlushingWithAnnotations(SCHEMA_FOLDER); } public final void testBeanNameAutoProxyCreatorWithDtd() throws Exception { performCachingAndFlushingWithBeanNameAutoProxyCreator(DTD_FOLDER); } public final void testBeanNameAutoProxyCreatorWithSchema() throws Exception { performCachingAndFlushingWithBeanNameAutoProxyCreator(SCHEMA_FOLDER); } public final void testCacheProxyFactoryBeanWithDtd() throws Exception { performCachingAndFlushingWithCacheProxyFactoryBean(DTD_FOLDER); } public final void testCacheProxyFactoryBeanWithSchema() throws Exception { performCachingAndFlushingWithCacheProxyFactoryBean(SCHEMA_FOLDER); } public final void testCommonsAttributesWithDtd() throws Exception { performCachingAndFlushingWithCommonsAttributes(DTD_FOLDER); } public final void testCommonsAttributesWithSchema() throws Exception { performCachingAndFlushingWithCommonsAttributes(SCHEMA_FOLDER); } protected final void assertCacheEntryFromCacheIsNull(Object cacheEntry, Serializable key) { assertNull("There should not be any object stored under the key <" + StringUtils.quoteIfString(key) + ">", cacheEntry); } protected abstract void assertCacheWasFlushed() throws Exception; /** * Asserts that the given object was cached. * * @param expectedCachedObject * the object that should have been cached. * @param keyAndModelIndex * the index of the key/model stored in <code>cachingListener</code>. * @see KeyAndModelListCachingListener */ protected abstract void assertObjectWasCached(Object expectedCachedObject, int keyAndModelIndex) throws Exception; protected final ApplicationContext getApplicationContext() { return applicationContext; } protected final Object cacheManager() { return applicationContext.getBean(CACHE_MANAGER_BEAN_NAME); } protected final KeyAndModelListCachingListener getCachingListener() { return cachingListener; } protected final KeyAndModel getKeyAndModel(int index) { List keyAndModelPairs = cachingListener.getKeyAndModelPairs(); KeyAndModel keyModel = (KeyAndModel)keyAndModelPairs.get(index); return keyModel; } /** * Verifies that the caching and the cache-flushing are working correctly. */ private void performCachingAndFlushing(String configStrategyConfig) throws Exception { setUpApplicationContext(configStrategyConfig); cachingListener = (KeyAndModelListCachingListener)applicationContext .getBean("cachingListener"); target = (CacheableService)applicationContext.getBean("cacheableService"); logger.debug("Storing in the cache..."); int nameIndex = 0; String cachedObject = target.getName(nameIndex); assertTrue("The retrieved name should not be empty", StringUtils .hasText(cachedObject)); assertObjectWasCached(cachedObject, nameIndex); // call the same method again. This time the return value should be read // from the cache. logger.debug("Reading from the cache..."); cachedObject = target.getName(nameIndex); // verify that the element was cached only once. There should be only // one caching event registered in the listener. int expectedTimesObjectWasCached = 1; int actualTimesObjectWasCached = cachingListener.getKeyAndModelPairs() .size(); assertEquals("<Number of times the same object was cached>", expectedTimesObjectWasCached, actualTimesObjectWasCached); // call the method 'updateName(int, String)'. When executed, the cache // should be flushed. logger.debug("Flushing the cache ..."); target.updateName(nameIndex, "Darth Maul"); assertCacheWasFlushed(); // NULL_ENTRY should be cached, and null should be returned. target.updateName(++nameIndex, null); cachedObject = target.getName(nameIndex); assertObjectWasCached(AbstractCachingInterceptor.NULL_ENTRY, nameIndex); assertNull(cachedObject); } private void performCachingAndFlushingWithAnnotations(String configFolder) throws Exception { if (SystemUtils.atLeastJ2SE5()) { performCachingAndFlushing(configFolder + ANNOTATIONS_CONTEXT); return; } logger.info("Unable to run tests using file \"" + ANNOTATIONS_CONTEXT + ".\" Annotations are not supported by this version of Java"); } private void performCachingAndFlushingWithBeanNameAutoProxyCreator( String configFolder) throws Exception { String configLocation = configFolder + BEAN_NAME_AUTOPROXY_CREATOR_CONTEXT; performCachingAndFlushing(configLocation); } private void performCachingAndFlushingWithCacheProxyFactoryBean( String configFolder) throws Exception { String configLocation = configFolder + CACHE_PROXY_FACTORY_BEAN_CONTEXT; performCachingAndFlushing(configLocation); } private void performCachingAndFlushingWithCommonsAttributes( String configFolder) throws Exception { String configLocation = configFolder + COMMONS_ATTRIBUTES_CONTEXT; performCachingAndFlushing(configLocation); } private void setUpApplicationContext(String configStrategyConfig) { String folder = configStrategyConfig.startsWith(DTD_FOLDER) ? DTD_FOLDER : SCHEMA_FOLDER; String root = "classpath:" + PathUtils.getPackageNameAsPath(getClass()); String[] configLocations = { root + folder + "cacheContext.xml", root + configStrategyConfig }; applicationContext = new ClassPathXmlApplicationContext(configLocations); } }