All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.fulcrum.cache.impl.EHCacheService Maven / Gradle / Ivy

There is a newer version: 2.0.1
Show newest version
package org.apache.fulcrum.cache.impl;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

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

import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.fulcrum.cache.CachedObject;
import org.apache.fulcrum.cache.GlobalCacheService;
import org.apache.fulcrum.cache.ObjectExpiredException;
import org.apache.fulcrum.cache.RefreshableCachedObject;

/**
 * Default implementation of EHCacheService
 * 
 * @author Eric Pugh
 * @author Thomas Vandahl
 * 
 */
public class EHCacheService extends AbstractLogEnabled implements
        GlobalCacheService, Runnable, Configurable, Disposable, Initializable, ThreadSafe
{
    /**
     * Cache check frequency in Millis (1000 Millis = 1 second). Value must be >
     * 0. Default = 5 seconds
     */
    public static final long DEFAULT_CACHE_CHECK_FREQUENCY = 5000; // 5 seconds

    /**
     * cacheCheckFrequency (default - 5 seconds)
     */
    private long cacheCheckFrequency;

    /**
     * Path name of the JCS configuration file
     */
    private String configFile;

    /**
     * Constant value which provides a cache name
     */
    private static final String DEFAULT_CACHE_NAME = "fulcrum";

    /**
     * A cache name
     */
    private String cacheName;

    /** thread for refreshing stale items in the cache */
    private Thread refreshing;

    /** flag to stop the housekeeping thread when the component is disposed. */
    private boolean continueThread;

    /** The EHCache manager instance */
    private CacheManager cacheManager;

    /** A cache instance */
    private Cache cache;

    // ---------------- Avalon Lifecycle Methods ---------------------

    /**
     * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
     */
    public void configure(Configuration config) throws ConfigurationException
    {
        this.cacheCheckFrequency = config.getChild("cacheCheckFrequency")
                .getValueAsLong(DEFAULT_CACHE_CHECK_FREQUENCY);
        this.cacheName = config.getChild("cacheName").getValue(DEFAULT_CACHE_NAME);
        this.configFile = config.getChild("configurationFile").getValue(null);
    }

    /**
     * @see org.apache.avalon.framework.activity.Initializable#initialize()
     */
    public void initialize() throws Exception
    {
        if (this.configFile == null)
        {
            this.cacheManager = new CacheManager();
            this.cacheManager.addCache(this.cacheName);
        }
        else
        {
            this.cacheManager = new CacheManager(this.configFile);
        }
        
        this.cache = this.cacheManager.getCache(this.cacheName);
        
        // Start housekeeping thread.
        this.continueThread = true;
        this.refreshing = new Thread(this);

        // Indicate that this is a system thread. JVM will quit only when
        // there are no more active user threads. Settings threads spawned
        // internally by Turbine as daemons allows commandline applications
        // using Turbine to terminate in an orderly manner.
        this.refreshing.setDaemon(true);
        this.refreshing.setName("EHCacheService Refreshing");
        this.refreshing.start();
        
        getLogger().debug("EHCacheService started!");
    }

    /**
     * @see org.apache.avalon.framework.activity.Disposable#dispose()
     */
    public void dispose()
    {
        this.continueThread = false;
        this.refreshing.interrupt();

        this.cacheManager.shutdown();
        this.cacheManager = null;
        this.cache = null;
        getLogger().debug("EHCacheService stopped!");
    }
    
    /**
     * @see org.apache.fulcrum.cache.GlobalCacheService#addObject(java.lang.String, org.apache.fulcrum.cache.CachedObject)
     */
    public void addObject(String id, CachedObject o)
    {
        Element cacheElement = new Element(id, o);

        if (o instanceof RefreshableCachedObject)
        {
            cacheElement.setEternal(true);
        }
        else
        {
            cacheElement.setEternal(false);
            cacheElement.setTimeToLive((int)(o.getExpires() + 500) / 1000);
        }

        cacheElement.setCreateTime();

        this.cache.put(cacheElement);
    }

    /**
     * @see org.apache.fulcrum.cache.GlobalCacheService#flushCache()
     */
    public void flushCache()
    {
        this.cache.removeAll();
    }

    /**
     * @see org.apache.fulcrum.cache.GlobalCacheService#getCachedObjects()
     */
    public List getCachedObjects()
    {
        ArrayList values = new ArrayList();

        for (Iterator i = getKeys().iterator(); i.hasNext();)
        {
            Element cachedElement = this.cache.get(i.next());
            
            if (cachedElement != null)
            {
                values.add(cachedElement.getObjectValue());
            }
        }

        return values;
    }

    /**
     * @see org.apache.fulcrum.cache.GlobalCacheService#getCacheSize()
     */
    public int getCacheSize() throws IOException
    {
        return (int)this.cache.calculateInMemorySize();
    }

    /**
     * @see org.apache.fulcrum.cache.GlobalCacheService#getKeys()
     */
    public List getKeys()
    {
        return this.cache.getKeysWithExpiryCheck();
    }

    /**
     * @see org.apache.fulcrum.cache.GlobalCacheService#getNumberOfObjects()
     */
    public int getNumberOfObjects()
    {
        return getKeys().size();
    }

    /**
     * @see org.apache.fulcrum.cache.GlobalCacheService#getObject(java.lang.String)
     */
    public CachedObject getObject(String id) throws ObjectExpiredException
    {
        Element cachedElement = this.cache.get(id);
        
        if (cachedElement == null)
        {
            // Not in the cache.
            throw new ObjectExpiredException();
        }

        CachedObject obj = (CachedObject)cachedElement.getObjectValue();
        
        if (obj.isStale())
        {
            if (obj instanceof RefreshableCachedObject)
            {
                RefreshableCachedObject rco = (RefreshableCachedObject) obj;
                if (rco.isUntouched())
                {
                    // Do not refresh an object that has exceeded TimeToLive
                    removeObject(id);
                    throw new ObjectExpiredException();
                }

                // Refresh Object
                rco.refresh();
                if (rco.isStale())
                {
                    // Object is Expired, remove it from cache.
                    removeObject(id);
                    throw new ObjectExpiredException();
                }
            }
            else
            {
                // Expired.
                removeObject(id);
                throw new ObjectExpiredException();
            }
        }

        if (obj instanceof RefreshableCachedObject)
        {
            // notify it that it's being accessed.
            RefreshableCachedObject rco = (RefreshableCachedObject) obj;
            rco.touch();
        }

        return obj;
    }

    /**
     * @see org.apache.fulcrum.cache.GlobalCacheService#removeObject(java.lang.String)
     */
    public void removeObject(String id)
    {
        this.cache.remove(id);
    }

    /**
     * Circle through the cache and refresh stale objects. Frequency is
     * determined by the cacheCheckFrequency property.
     */
    public void run()
    {
        while (this.continueThread)
        {
            // Sleep for amount of time set in cacheCheckFrequency -
            // default = 5 seconds.
            try
            {
                Thread.sleep(this.cacheCheckFrequency);
            }
            catch (InterruptedException exc)
            {
                if (!this.continueThread)
                {
                    return;
                }
            }

            for (Iterator i = getKeys().iterator(); i.hasNext();)
            {
                String key = (String) i.next();
                
                Element cachedElement = this.cache.get(key);
                
                if (cachedElement == null)
                {
                    this.cache.remove(key);
                    continue;
                }
                
                Object o = cachedElement.getObjectValue();
                
                if (o instanceof RefreshableCachedObject)
                {
                    RefreshableCachedObject rco = (RefreshableCachedObject) o;
                    if (rco.isUntouched())
                    {
                        this.cache.remove(key);
                    }
                    else if (rco.isStale())
                    {
                        rco.refresh();
                    }
                }
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy