org.springmodules.cache.provider.AbstractCacheProviderFacade.java Source code

Java tutorial

Introduction

Here is the source code for org.springmodules.cache.provider.AbstractCacheProviderFacade.java

Source

/*
 * Created on Nov 10, 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 @2007 the original author or authors.
 */
package org.springmodules.cache.provider;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.StringUtils;

import org.springmodules.cache.CacheException;
import org.springmodules.cache.CachingModel;
import org.springmodules.cache.FatalCacheException;
import org.springmodules.cache.FlushingModel;
import org.springmodules.cache.serializable.SerializableFactory;

import java.io.Serializable;

/**
 * Template for implementations of <code>{@link CacheProviderFacade}</code>.
 *
 * @author Omar Irbouh
 * @author Alex Ruiz
 */
public abstract class AbstractCacheProviderFacade implements CacheProviderFacade, InitializingBean {

    /**
     * Logger available to subclasses
     */
    protected final Log logger = LogFactory.getLog(getClass());

    private boolean failQuietlyEnabled;

    private SerializableFactory serializableFactory;

    /**
     * Validates the properties of this class after being set by the
     * <code>BeanFactory</code>.
     *
     * @throws FatalCacheException if one or more properties of this facade are in an illegal state
     * @see #validateCacheManager()
     */
    public final void afterPropertiesSet() throws FatalCacheException {
        validateCacheManager();
        onAfterPropertiesSet();
    }

    /**
     * @see CacheProviderFacade#cancelCacheUpdate(Serializable)
     */
    public final void cancelCacheUpdate(Serializable key) throws CacheException {
        if (logger.isDebugEnabled()) {
            logger.debug("Attempt to cancel a cache update using the key <" + StringUtils.quoteIfString(key) + ">");
        }

        try {
            onCancelCacheUpdate(key);

        } catch (CacheException exception) {
            handleCatchedException(exception);
        }
    }

    /**
     * @see CacheProviderFacade#flushCache(FlushingModel)
     */
    public final void flushCache(FlushingModel model) throws CacheException {
        if (logger.isDebugEnabled()) {
            logger.debug("Attempt to flush the cache using model <" + model + ">");
        }

        if (model != null) {
            try {
                onFlushCache(model);
                logger.debug("Cache has been flushed.");

            } catch (CacheException exception) {
                handleCatchedException(exception);
            }
        }
    }

    /**
     * @see CacheProviderFacade#getFromCache(Serializable,CachingModel)
     */
    public final Object getFromCache(Serializable key, CachingModel model) throws CacheException {

        if (logger.isDebugEnabled()) {
            logger.debug("Attempt to retrieve a cache entry using key <" + StringUtils.quoteIfString(key)
                    + "> and cache model <" + model + ">");
        }

        Object cachedObject = null;

        try {
            if (model != null) {
                cachedObject = onGetFromCache(key, model);

                // deserialize the value if required
                if (cachedObject != null) {
                    cachedObject = deserializeValueIfNecessary(cachedObject);
                }
            }

            if (logger.isDebugEnabled()) {
                logger.debug("Retrieved cache element <" + StringUtils.quoteIfString(cachedObject) + ">");
            }

        } catch (CacheException exception) {
            handleCatchedException(exception);
        }
        return cachedObject;
    }

    /**
     * @see CacheProviderFacade#isFailQuietlyEnabled()
     */
    public final boolean isFailQuietlyEnabled() {
        return failQuietlyEnabled;
    }

    /**
     * @see CacheProviderFacade#putInCache(Serializable,CachingModel,Object)
     * @see #makeSerializableIfNecessary(Object)
     */
    public final void putInCache(Serializable key, CachingModel model, Object obj) throws CacheException {
        if (logger.isDebugEnabled()) {
            logger.debug("Attempt to store the object <" + obj + "> in the cache using key <"
                    + StringUtils.quoteIfString(key) + "> and model <" + model + ">");
        }

        try {
            Object newCacheElement = makeSerializableIfNecessary(obj);

            if (model != null) {
                onPutInCache(key, model, newCacheElement);
                logger.debug("Object was successfully stored in the cache");
            }
        } catch (CacheException exception) {
            handleCatchedException(exception);
        }
    }

    /**
     * @see CacheProviderFacade#removeFromCache(Serializable,CachingModel)
     */
    public final void removeFromCache(Serializable key, CachingModel model) throws CacheException {
        if (logger.isDebugEnabled()) {
            logger.debug("Attempt to remove an entry from the cache using key <" + StringUtils.quoteIfString(key)
                    + "> and model <" + model + ">");
        }

        if (model != null) {
            try {
                onRemoveFromCache(key, model);
                logger.debug("Object removed from the cache");

            } catch (CacheException exception) {
                handleCatchedException(exception);
            }
        }
    }

    /**
     * Sets the flag that indicates if any exception thrown at run-time by the
     * cache manager should be propagated (<code>false</code>) or not (<code>true</code>.)
     *
     * @param newFailQuietlyEnabled the new value for the flag
     */
    public final void setFailQuietlyEnabled(boolean newFailQuietlyEnabled) {
        failQuietlyEnabled = newFailQuietlyEnabled;
    }

    /**
     * Sets the factory that makes serializable the objects to be stored in the
     * cache (if the cache requires serializable elements).
     *
     * @param newSerializableFactory the new factory of serializable objects
     */
    public final void setSerializableFactory(SerializableFactory newSerializableFactory) {
        serializableFactory = newSerializableFactory;
    }

    /**
     * Asserts that the given cache manager is not <code>null</code>.
     *
     * @param cacheManager the cache manager to check
     * @throws FatalCacheException if the cache manager is <code>null</code>
     */
    protected final void assertCacheManagerIsNotNull(Object cacheManager) throws FatalCacheException {
        if (cacheManager == null) {
            throw new FatalCacheException("The cache manager should not be null");
        }
    }

    /**
     * Rethrows the given exception if "fail quietly" is enabled.
     *
     * @param exception the catched exception to be potentially rethrown.
     * @throws CacheException if this cache provider has not been configured to "fail quietly."
     */
    protected final void handleCatchedException(CacheException exception) throws CacheException {
        logger.error(exception.getMessage(), exception);
        if (!isFailQuietlyEnabled()) {
            throw exception;
        }
    }

    /**
     * @return <code>true</code> if the cache used by this facade can only store
     *         serializable objects.
     */
    protected abstract boolean isSerializableCacheElementRequired();

    /**
     * Makes the given object serializable if:
     * <ul>
     * <li>The cache can only store serializable objects</li>
     * <li>The given object does not implement <code>java.io.Serializable</code>
     * </li>
     * </ul>
     * Otherwise, will return the same object passed as argument.
     *
     * @param obj the object to check.
     * @return the given object as a serializable object if necessary.
     * @throws ObjectCannotBeCachedException if the cache requires serializable elements, the given object
     *                                       does not implement <code>java.io.Serializable</code> and the
     *                                       factory of serializable objects is <code>null</code>.
     * @see #setSerializableFactory(SerializableFactory)
     * @see org.springmodules.cache.serializable.SerializableFactory#makeSerializableIfNecessary(Object)
     */
    protected final Object makeSerializableIfNecessary(Object obj) {
        if (!isSerializableCacheElementRequired()) {
            return obj;
        }
        if (obj instanceof Serializable) {
            return obj;
        }
        if (serializableFactory != null) {
            return serializableFactory.makeSerializableIfNecessary(obj);
        }
        throw new ObjectCannotBeCachedException("The cache can only store implementations of java.io.Serializable");
    }

    /**
     * Deserialize the value from the given object if:
     * <ul>
     * <li>The cache can only store serializable objects</li>
     * <li>The given object does not implement <code>java.io.Serializable</code>
     * </li>
     * </ul>
     * Otherwise, will throw an {@link InvalidObjectInCacheException}.
     *
     * @param obj the object to check.
     * @return the given object as a serializable object if necessary.
     * @throws InvalidObjectInCacheException if the cache requires serializable elements, the given object
     *                                       does not implement <code>java.io.Serializable</code> and the
     *                                       factory of serializable objects is <code>null</code>.
     * @see #setSerializableFactory(SerializableFactory)
     * @see org.springmodules.cache.serializable.SerializableFactory#getOriginalValue(Object)
     */
    protected final Object deserializeValueIfNecessary(Object obj) {
        if (!isSerializableCacheElementRequired()) {
            return obj;
        }
        if (obj instanceof Serializable) {
            if (serializableFactory != null) {
                return serializableFactory.getOriginalValue(obj);
            }
            return obj;
        }
        throw new InvalidObjectInCacheException(
                "The object retrieved from the cache is not of the required " + "type: java.io.Serializable.");
    }

    /**
     * Gives subclasses the opportunity to initialize their own properties. Called
     * after <code>{@link #afterPropertiesSet()}</code> has finished setting up
     * the properties of an instance of this class.
     *
     * @throws FatalCacheException if one or more properties of the facade or its dependencies have
     *                             incorrect values.
     */
    protected void onAfterPropertiesSet() throws FatalCacheException {
        // no implementation.
    }

    /**
     * Cancels the update being made to the cache.
     *
     * @param key the key being used in the cache update.
     * @throws CacheException if an unexpected error takes place when attempting to cancel the
     *                        update.
     */
    protected void onCancelCacheUpdate(Serializable key) throws CacheException {
        logger.info("Cache provider does not support cancelation of updates");
    }

    /**
     * Flushes the caches specified in the given model.
     *
     * @param model the model that specifies what and how to flush.
     * @throws CacheException if an unexpected error takes place when flushing the cache.
     */
    protected abstract void onFlushCache(FlushingModel model) throws CacheException;

    /**
     * Retrieves an entry from the cache.
     *
     * @param key   the key under which the entry is stored.
     * @param model the model that specifies how to retrieve an entry.
     * @return the cached entry.
     * @throws CacheException if an unexpected error takes place when retrieving the entry from
     *                        the cache.
     */
    protected abstract Object onGetFromCache(Serializable key, CachingModel model) throws CacheException;

    /**
     * Stores an object in the cache.
     *
     * @param key   the key used to store the object.
     * @param model the model that specifies how to store an object in the cache.
     * @param obj   the object to store in the cache.
     * @throws CacheException if an unexpected error takes place when storing an object in the
     *                        cache.
     */
    protected abstract void onPutInCache(Serializable key, CachingModel model, Object obj) throws CacheException;

    /**
     * Removes an entry from the cache.
     *
     * @param key   the key the entry to remove is stored under.
     * @param model the model that specifies how to remove the entry from the cache.
     * @throws CacheException if an unexpected error takes place when removing an entry from
     *                        the cache.
     */
    protected abstract void onRemoveFromCache(Serializable key, CachingModel model) throws CacheException;

    /**
     * Validates the cache manager used by this facade.
     *
     * @throws FatalCacheException if the cache manager is in an invalid state.
     */
    protected abstract void validateCacheManager() throws FatalCacheException;
}