org.onebusaway.container.cache.CacheableMethodManager.java Source code

Java tutorial

Introduction

Here is the source code for org.onebusaway.container.cache.CacheableMethodManager.java

Source

/**
 * Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
 *
 * 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.
 */
package org.onebusaway.container.cache;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;

/**
 * Support class providing functionality for caching the output of arbitrary
 * method calls, using the arguments to the method to generate the cache key.
 * 
 * EhCache is used as the backing cache store.
 * 
 * @author bdferris
 * @see Cacheable
 * @see CacheableAnnotationInterceptor
 * @see CacheableMethodKeyFactory
 * @see CacheableMethodKeyFactoryManager
 */
public class CacheableMethodManager {

    private ConcurrentHashMap<String, CacheEntry> _entries = new ConcurrentHashMap<String, CacheEntry>();

    private CacheManager _cacheManager;

    protected CacheableMethodKeyFactoryManager _cacheableMethodKeyFactoryManager;

    private String _cacheNamePrefix;

    public void setCacheManager(CacheManager cacheManager) {
        _cacheManager = cacheManager;
    }

    public void setCacheableMethodKeyFactoryManager(
            CacheableMethodKeyFactoryManager cacheableMethodKeyFactoryManager) {
        _cacheableMethodKeyFactoryManager = cacheableMethodKeyFactoryManager;
    }

    public void setCacheNamePrefix(String cacheNamePrefix) {
        _cacheNamePrefix = cacheNamePrefix;
    }

    public Object evaluate(ProceedingJoinPoint pjp) throws Throwable {

        CacheEntry entry = getCache(pjp);
        CacheableMethodKeyFactory keyFactory = entry.getKeyFactory();
        Cache cache = entry.getCache();
        CacheKeyInfo keyInfo = keyFactory.createKey(pjp);
        Serializable key = keyInfo.getKey();

        Element element = cache.get(key);

        if (element == null || keyInfo.isCacheRefreshIndicated()) {
            Object retVal = pjp.proceed();
            element = new Element(key, retVal);
            cache.put(element);
        }

        if (entry.isValueSerializable())
            return element.getValue();
        else
            return element.getObjectValue();
    }

    /***************************************************************************
     * Protected Methods
     * 
     * @param method
     **************************************************************************/

    protected CacheableMethodKeyFactory getKeyFactory(ProceedingJoinPoint pjp, Method method) {
        return _cacheableMethodKeyFactoryManager.getCacheableMethodKeyFactoryForJoinPoint(pjp, method);
    }

    protected String getCacheName(ProceedingJoinPoint pjp) {
        Signature sig = pjp.getSignature();
        StringBuilder b = new StringBuilder();
        if (_cacheNamePrefix != null)
            b.append(_cacheNamePrefix).append("-");
        b.append(sig.getDeclaringTypeName()).append('.').append(sig.getName());
        return b.toString();
    }

    protected Cache createCache(ProceedingJoinPoint pjp, String name) {
        return null;
    }

    /****
     * Private Methods
     ****/

    private CacheEntry getCache(ProceedingJoinPoint pjp) {

        String name = getCacheName(pjp);

        CacheEntry entry = _entries.get(name);

        if (entry == null) {
            Method method = _cacheableMethodKeyFactoryManager.getMatchingMethodForJoinPoint(pjp);
            CacheableMethodKeyFactory keyFactory = getKeyFactory(pjp, method);
            boolean valueSerializable = isValueSerializable(pjp, method);
            Cache cache = _cacheManager.getCache(name);
            if (cache == null) {
                cache = createCache(pjp, name);
                if (cache == null) {
                    if (!_cacheManager.cacheExists(name))
                        _cacheManager.addCache(name);
                    cache = _cacheManager.getCache(name);
                } else {
                    _cacheManager.addCache(cache);
                }
            }
            entry = new CacheEntry(keyFactory, valueSerializable, cache);
            _entries.put(name, entry);
        }
        return entry;
    }

    private boolean isValueSerializable(ProceedingJoinPoint pjp, Method method) {
        Cacheable c = method.getAnnotation(Cacheable.class);
        if (c == null)
            return true;
        return c.isValueSerializable();
    }

    private static class CacheEntry {

        private CacheableMethodKeyFactory _keyFactory;

        private boolean _valueSerializable;

        private Cache _cache;

        public CacheEntry(CacheableMethodKeyFactory keyFactory, boolean valueSerializable, Cache cache) {
            _keyFactory = keyFactory;
            _valueSerializable = valueSerializable;
            _cache = cache;
        }

        public CacheableMethodKeyFactory getKeyFactory() {
            return _keyFactory;
        }

        public boolean isValueSerializable() {
            return _valueSerializable;
        }

        public Cache getCache() {
            return _cache;
        }
    }
}