Package org.apache.stratum.jcs.engine.control

Source Code of org.apache.stratum.jcs.engine.control.Cache

package org.apache.stratum.jcs.engine.control;

/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Velocity", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
import java.io.IOException;
import java.io.Serializable;

import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.stratum.jcs.access.exception.CacheException;
import org.apache.stratum.jcs.access.exception.ObjectNotFoundException;
import org.apache.stratum.jcs.access.exception.ObjectExistsException;

import org.apache.stratum.jcs.engine.behavior.IElementAttributes;
import org.apache.stratum.jcs.engine.CacheElement;

import org.apache.stratum.jcs.engine.behavior.ICache;
import org.apache.stratum.jcs.engine.behavior.ICacheElement;
import org.apache.stratum.jcs.engine.behavior.ICacheHub;
import org.apache.stratum.jcs.engine.behavior.ICacheType;
import org.apache.stratum.jcs.engine.behavior.ICompositeCache;
import org.apache.stratum.jcs.engine.behavior.ICompositeCacheAttributes;

import org.apache.stratum.jcs.engine.memory.MemoryElementDescriptor;
import org.apache.stratum.jcs.engine.memory.behavior.IMemoryCache;
import org.apache.stratum.jcs.engine.memory.lru.LRUMemoryCache;

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

/**
* This is the primary cache hub. It control the flow of items through the
* cache. The auxiliary and memory caches are plugged in here.
*
* @author asmuts
* @created January 15, 2002
*/
public class Cache
     implements ICacheHub, ICache, ICompositeCache, Serializable
{
    private final static Log log = LogFactory.getLog( Cache.class );

    /**
     * not used for much
     */
    public final String className;

    // Auxiliary caches.
    private ICache[] auxCaches;
    // track hit counts for each
    private int[] auxHit;

    private boolean alive = true;

    // this is int he cacheAttr, shouldn't be used, remove
    final String cacheName;

    /**
     * Region Elemental Attributes, default
     */
    public IElementAttributes attr;

    /**
     * Cache Attributes, for hub and memory auxiliary
     */
    public ICompositeCacheAttributes cacheAttr;

    // statistics
    private static int numInstances;
    private int ramHit;
    private int miss;

    /**
     * The cache hub can only have one memory cache. This could be made more
     * flexible in the future, but they are tied closely together. More than one
     * doesn't make much sense.
     */
    // IMemoryCache
    IMemoryCache memCache;

    /**
     * Constructor for the Cache object
     *
     * @param cacheName The name of the region
     * @param auxCaches The auxiliary caches to be used by this region
     * @param cattr The cache attribute
     * @param attr The default element attributes
     */
    public Cache( String cacheName, ICache[] auxCaches, ICompositeCacheAttributes cattr, IElementAttributes attr )
    {

        numInstances++;
        String s = this.getClass().getName();
        int idx = s.lastIndexOf( "." );
        this.className = s.substring( idx + 1 );
        this.cacheName = cacheName;

        this.auxCaches = auxCaches;
        if ( auxCaches != null )
        {
            this.auxHit = new int[auxCaches.length];
        }

        this.attr = attr;
        this.cacheAttr = cattr;

        createMemoryCache( cattr );

        if ( log.isDebugEnabled() )
        {
            log.debug( "Constructed cache with name " + cacheName +
                " and cache attributes: " + cattr );
        }
        else if ( log.isInfoEnabled() )
        {
            log.info( "Constructed cache with name: " + cacheName );
        }
    }

    /**
     * Description of the Method
     *
     * @deprecated
     * @see this will become protected
     * @param ce
     */
    public void add( ICacheElement ce )
    {
        try
        {
            memCache.update( ce );
        }
        catch ( Exception e )
        {
            log.error( e );
        }
        return;
    }


    /**
     * Will no override existing items.
     *
     * @param key
     * @param val
     * @exception IOException
     * @exception ObjectExistsException
     */
    public void putSafe( Serializable key, Serializable val )
        throws IOException, ObjectExistsException
    {
        if ( this.get( key ) != null )
        {
            throw new ObjectExistsException( "Object exists for key " + key );
        }
        else
        {
            put( key, val, ( IElementAttributes ) this.attr.copy() );
        }
        return;
    }


    /**
     * Put in cache and configured auxiliaries.
     *
     * @param key
     * @param val
     * @exception IOException
     */
    public void put( Serializable key, Serializable val )
        throws IOException
    {
        put( key, val, ( IElementAttributes ) this.attr.copy() );
        return;
    }


    /**
     * Description of the Method
     *
     * @param key Cache key
     * @param val Value to cache
     * @param attr Element attributes
     * @exception IOException
     */
    public void put( Serializable key, Serializable val, IElementAttributes attr )
        throws IOException
    {

        if ( key == null || val == null )
        {
            NullPointerException npe =
                new NullPointerException( "key=" + key + " and val=" + val +
                " must not be null." );

            log.error( "Key or value was null. Exception will be thrown", npe );

            throw npe;
        }

        try
        {
            updateCaches( key, val, attr );
        }
        catch ( IOException ioe )
        {
            log.error( "Failed updating caches", ioe );
        }
        return;
    }


    /**
     * Description of the Method
     *
     * @param key Cache key
     * @param val Value to cache
     * @param attr Element attributes
     * @exception IOException
     */
    protected synchronized void updateCaches( Serializable key, Serializable val, IElementAttributes attr )
        throws IOException
    {
        // FIXME: Replace with tracing aspects

        if ( log.isDebugEnabled() )
        {
            log.debug( "updateCaches(key,val,attr) > ICache.INCLUDE_REMOTE_CACHE= " + ICache.INCLUDE_REMOTE_CACHE + " key = " + key );
        }

        updateCaches( key, val, attr, ICache.INCLUDE_REMOTE_CACHE );

    }


    /**
     * Description of the Method
     *
     * @param key
     * @param val
     * @param attr
     * @param updateRemoteCache
     * @exception IOException
     */
    protected synchronized void updateCaches( Serializable key, Serializable val, IElementAttributes attr, boolean updateRemoteCache )
        throws IOException
    {
        // FIXME: Replace with tracing aspects

        if ( log.isDebugEnabled() )
        {
            log.debug( "updateCaches(key,val,attr,updateRemoteCache) > updateRemoteCache= " + updateRemoteCache + " key = " + key );
        }

        CacheElement ce = new CacheElement( cacheName, key, val );
        ce.setElementAttributes( attr );
        updateExclude( ce, updateRemoteCache );
    }


    /**
     * Standard update method
     *
     * @param ce
     * @exception IOException
     */
    public synchronized void update( ICacheElement ce )
        throws IOException
    {
        // FIXME: Replace with tracing aspects

        if ( log.isDebugEnabled() )
        {
            log.debug( "update(ce) > ICache.INCLUDE_REMOTE_CACHE= " + ICache.INCLUDE_REMOTE_CACHE + " key = " + ce.getKey() );
        }
        update( ce, ICache.INCLUDE_REMOTE_CACHE );
    }


    /**
     * Description of the Method
     *
     * @param updateRemoteCache Should the nonlocal caches be updated
     * @param ce
     * @exception IOException
     */
    public void update( ICacheElement ce, boolean updateRemoteCache )
        throws IOException
    {
        updateExclude( ce, updateRemoteCache );
    }


    /**
     * Description of the Method
     *
     * @param ce
     * @param updateRemoteCache
     * @exception IOException
     */
    public synchronized void updateExclude( ICacheElement ce, boolean updateRemoteCache )
        throws IOException
    {

        if ( ce.getKey() instanceof String && ce.getKey().toString().endsWith( NAME_COMPONENT_DELIMITER ) )
        {
            throw new IllegalArgumentException(
                "key must not end with " + NAME_COMPONENT_DELIMITER + " for a put operation" );
        }

        // FIXME: Replace with tracing aspects

        if ( log.isDebugEnabled() )
        {
            log.debug( "Cache.updateExclude(ce,updateRemoteCache) > updateRemoteCache = " + updateRemoteCache + " key=" + ce.getKey() + ", value type=" + ce.getVal().getClass().getName() + ", " + ce.getElementAttributes().toString() );

            if ( updateRemoteCache == ICache.INCLUDE_REMOTE_CACHE )
            {
                log.debug( "updateRemoteCache is TRUE " + updateRemoteCache );
            }
            else
            {
                log.debug( "updateRemoteCache is FALSE " + updateRemoteCache );
            }
        }

        memCache.update( ce );

        // Updates to all auxiliary caches -- remote and laterals, can add as many of each
        // as necessary.
        // could put the update criteria in each but it would a bit cumbersome
        // the disk cache would have to check the cache size, the lateral
        // would have to check the region cattr configuration

        // UPDATE AUXILLIARY CACHES
        // There are 3 types of auxiliary caches: remote, lateral, and disk
        // more can be added if future auxiliary caches don't fit the model
        // You could run a database cache as either a remote or a local disk.
        // The types would describe the purpose.
        for ( int i = 0; i < auxCaches.length; i++ )
        {
            ICache aux = auxCaches[i];

            if ( log.isDebugEnabled() )
            {
                log.debug( "aux.getCacheType() = " + aux.getCacheType() );
            }

            // SEND TO REMOTE STORE
            if ( aux != null && aux.getCacheType() == ICache.REMOTE_CACHE )
            {
                if ( log.isDebugEnabled() )
                {
                    log.debug( "ce.getElementAttributes().getIsRemote() = " + ce.getElementAttributes().getIsRemote() );
                }

                if ( ce.getElementAttributes().getIsRemote() && updateRemoteCache )
                {
                    try
                    {
                        // need to make sure the group cache understands that the
                        // key is a group attribute on update
                        aux.update( ce );
                        if ( log.isDebugEnabled() )
                        {
                            log.debug( "Updated remote store for " + ce.getKey() + ce );
                        }

                    }
                    catch ( IOException ex )
                    {
                        handleException( ex );
                    }
                }
                // SEND LATERALLY
            }
            else
                if ( aux != null && aux.getCacheType() == ICache.LATERAL_CACHE )
            {
                // lateral can't do the checking since it is dependent on the cache region
                // restrictions
                if ( log.isDebugEnabled() )
                {
                    log.debug( "lateralcache in aux list: cattr " +
                        cacheAttr.getUseLateral() );
                }
                if ( cacheAttr.getUseLateral() && ce.getElementAttributes().getIsLateral() && updateRemoteCache )
                {

                    // later if we want a multicast, possibly delete abnormal broadcaster
                    // DISTRIBUTE LATERALLY
                    // Currently always multicast even if the value is unchanged,
                    // just to cause the cache item to move to the front.
                    aux.update( ce );
                    if ( log.isDebugEnabled() )
                    {
                        log.debug( "updated lateral cache for " + ce.getKey() );
                    }
                }
                // end if lateral

                // DISK CACHE
            }
            else
                if ( aux != null && aux.getCacheType() == ICache.DISK_CACHE )
            {
                // do nothing, the memory manager will call spool where necesary
                // TODO: add option to put all element on disk
            }
        }
        // end for aux list

        return;
    }
    // update

    /**
     * ICacheHub method
     *
     * @param ce The CacheElement
     */
    public synchronized void spoolToDisk( ICacheElement ce )
    {

        // SPOOL TO DISK.
        for ( int i = 0; i < auxCaches.length; i++ )
        {
            ICache aux = auxCaches[i];

            if ( aux != null && aux.getCacheType() == ICache.DISK_CACHE )
            {
                // write the last item to disk.2
                try
                {
                    aux.update( ce );
                }
                catch ( IOException ex )
                {
                    // impossible case.
                    ex.printStackTrace();
                    throw new IllegalStateException( ex.getMessage() );
                }
                catch ( Exception oee )
                {
                }
                if ( log.isDebugEnabled() )
                {
                    log.debug( "moveToMemory -- request to put " + ce.getKey() + " on disk cache[" + i + "]" );
                }
            }
        }

    }
    // end spoolToDisk

    /**
     * Gets an item from the cache, and make it the first in the link list.
     *
     * @return The cacheElement value
     * @param key
     * @exception ObjectNotFoundException
     * @exception IOException
     */
    public Serializable getCacheElement( Serializable key )
        throws ObjectNotFoundException, IOException
    {
        return get( key, this.LOCAL_INVOKATION );
    }
    // end get ce

    /**
     * Description of the Method
     *
     * @return
     * @param key
     */
    public Serializable get( Serializable key )
    {
        return get( key, false, this.LOCAL_INVOKATION );
    }


    /**
     * Description of the Method
     *
     * @return
     * @param key
     * @param container
     */
    public Serializable get( Serializable key, boolean container )
    {
        return get( key, container, this.LOCAL_INVOKATION );
    }


    /**
     * Description of the Method
     *
     * @return
     * @param key
     * @param container
     * @param invocation
     */
    public Serializable get( Serializable key, boolean container, boolean invocation )
    {
        if ( log.isDebugEnabled() )
        {
            log.debug( "in cache get(key,container)" );
        }

        ICacheElement ce = null;
        boolean found = false;

        try
        {

            if ( log.isDebugEnabled() )
            {
                log.debug( "get: key = " + key + ", is local invocation = "
                     + ( invocation == this.LOCAL_INVOKATION ) );
            }

            ce = ( ICacheElement ) memCache.get( key, true );

            if ( ce == null )
            {
                // Item not found in memory.  Try the auxiliary caches if local.

                for ( int i = 0; i < auxCaches.length; i++ )
                {
                    ICache aux = auxCaches[i];

                    if ( aux != null )
                    {

                        if ( ( invocation == this.LOCAL_INVOKATION ) || aux.getCacheType() == aux.DISK_CACHE )
                        {
                            if ( log.isDebugEnabled() )
                            {
                                log.debug( "get(key,container,invocation) > in local block, aux.getCacheType() = " + aux.getCacheType() );
                            }

                            try
                            {
                                ce = ( ICacheElement ) aux.get( key, true );
                            }
                            catch ( IOException ex )
                            {
                                handleException( ex );
                            }
                        }

                        if ( log.isDebugEnabled() )
                        {
                            log.debug( "ce = " + ce );
                        }

                        if ( ce != null )
                        {
                            found = true;
                            // Item found in one of the auxiliary caches.
                            auxHit[i]++;

                            if ( log.isDebugEnabled() )
                            {
                                log.debug( cacheName + " -- AUX[" + i + "]-HIT for " + key );
                                log.debug( "ce.getKey() = " + ce.getKey() );
                                log.debug( "ce.getVal() = " + ce.getVal() );
                            }

                            memCache.update( ce );

                            break;
                        }
                    }
                    // end for
                }
                // end if invocation = LOCAL

            }
            else
            {
                found = true;
                ramHit++;
                if ( log.isDebugEnabled() )
                {
                    log.debug( cacheName + " -- RAM-HIT for " + key );
                }
            }

        }
        catch ( Exception e )
        {
            log.error( e );
        }

        try
        {

            if ( !found )
            {
                // Item not found in all caches.
                miss++;
                if ( log.isDebugEnabled() )
                {
                    log.debug( cacheName + " -- MISS for " + key );
                }
                return null;
                //throw new ObjectNotFoundException( key + " not found in cache" );
            }
        }
        catch ( Exception e )
        {
            log.error( "Error handling miss", e );
            return null;
        }

        // HUB Manages expiration
        try
        {

            if ( !ce.getElementAttributes().getIsEternal() )
            {

                long now = System.currentTimeMillis();

                // Exceeded maxLifeSeconds
                if ( ( ce.getElementAttributes().getMaxLifeSeconds() != -1 ) && ( now - ce.getElementAttributes().getCreateTime() ) > ( ce.getElementAttributes().getMaxLifeSeconds() * 1000 ) )
                {
                    if ( log.isInfoEnabled() )
                    {
                        log.info( "Exceeded maxLifeSeconds -- " + ce.getKey() );
                    }
                    this.remove( key );
                    //cache.remove( me.ce.getKey() );
                    return null;
                }
                else
                // NOT SURE IF THIS REALLY BELONGS HERE.  WHAT IS THE
                // POINT OF IDLE TIME?  SEEMS OK
                // Exceeded maxIdleTime, removal
                    if ( ( ce.getElementAttributes().getIdleTime() != -1 ) && ( now - ce.getElementAttributes().getLastAccessTime() ) > ( ce.getElementAttributes().getIdleTime() * 1000 ) )
                {
                    if ( log.isInfoEnabled() )
                    {
                        log.info( "Exceeded maxIdleTime [ ce.getElementAttributes().getIdleTime() = " + ce.getElementAttributes().getIdleTime() + " ]-- " + ce.getKey() );
                    }
                    this.remove( key );
                    //cache.remove( me.ce.getKey() );
                    return null;
                }
            }

        }
        catch ( Exception e )
        {
            log.error( "Error determining expiration period", e );
            return null;
        }

        if ( container )
        {
            return ce;
        }
        else
        {
            return ce.getVal();
        }

    }
    // end get



    /**
     * Removes an item from the cache.
     *
     * @return
     * @param key
     */
    public boolean remove( Serializable key )
    {
        return remove( key, LOCAL_INVOKATION );
    }


    /**
     * fromRemote: If a remove call was made on a cache with both, then the
     * remote should have been called. If it wasn't then the remote is down.
     * we'll assume it is down for all. If it did come from the remote then the
     * caceh is remotely configured and lateral removal is unncessary. If it
     * came laterally then lateral removal is unnecessary. Does this assumes
     * that there is only one lateral and remote for the cache? Not really, the
     * intial removal should take care of the problem if the source cache was
     * similiarly configured. Otherwise the remote cache, if it had no laterals,
     * would remove all the elements from remotely configured caches, but if
     * those caches had some other wierd laterals that were not remotely
     * configured, only laterally propagated then they would go out of synch.
     * The same could happen for multiple remotes. If this looks necessary we
     * will need to build in an identifier to specify the source of a removal.
     *
     * @return
     * @param key
     * @param nonLocal
     */
    // can't be protected because groupcache method needs to be called from access
    public synchronized boolean remove( Serializable key, boolean nonLocal )
    {

        if ( log.isDebugEnabled() )
        {
            log.debug( "remove> key=" + key + ", nonLocal=" + nonLocal );
        }

        boolean removed = false;

        try
        {
            removed = memCache.remove( key );
        }
        catch ( IOException e )
        {
            log.error( e );
        }

        // Removes from all auxiliary caches.
        for ( int i = 0; i < auxCaches.length; i++ )
        {
            ICache aux = auxCaches[i];

            if ( aux == null )
            {
                continue;
            }
            // avoid notification dead loop.
            int cacheType = aux.getCacheType();

            // for now let laterals call remote remove but not vice versa
            if ( nonLocal && ( cacheType == REMOTE_CACHE || cacheType == LATERAL_CACHE ) )
            {
                continue;
            }
            try
            {
                boolean b = aux.remove( key );

                // Don't take the remote removal into account.
                if ( !removed && cacheType != REMOTE_CACHE )
                {
                    removed = b;
                }
            }
            catch ( IOException ex )
            {
                handleException( ex );
            }
        }
        return removed;
    }
    // end remove

    /**
     * Removes all cached items.
     */
    public synchronized void removeAll()
    {


        try
        {
            memCache.removeAll();
        }
        catch ( IOException ex )
        {
            log.error( ex );
        }

        // Removes from all auxiliary disk caches.
        for ( int i = 0; i < auxCaches.length; i++ )
        {
            ICache aux = auxCaches[i];

            if ( aux != null && aux.getCacheType() == ICache.DISK_CACHE )
            {
                try
                {
                    aux.removeAll();
                }
                catch ( IOException ex )
                {
                    handleException( ex );
                }
            }
        }
        return;
    }


    /**
     * Flushes all cache items from memory to auxilliary caches and close the
     * auxilliary caches.
     */
    public void dispose()
    {
        dispose( LOCAL_INVOKATION );
    }


    /**
     * invoked only by CacheManager.
     *
     * @param fromRemote
     */
    protected void dispose( boolean fromRemote )
    {
        if ( !alive )
        {
            return;
        }
        synchronized ( this )
        {
            if ( !alive )
            {
                return;
            }
            alive = false;

            for ( int i = 0; i < auxCaches.length; i++ )
            {
                try
                {
                    ICache aux = auxCaches[i];

                    if ( aux == null || fromRemote && aux.getCacheType() == REMOTE_CACHE )
                    {
                        continue;
                    }
                    if ( aux.getStatus() == ICache.STATUS_ALIVE )
                    {

                        if ( log.isDebugEnabled() )
                        {
                            log.debug( "size = " + memCache.getSize() );
                        }

                        if ( !( aux.getCacheType() == ICacheType.LATERAL_CACHE && !this.cacheAttr.getUseLateral() ) )
                        {

                            Iterator itr = memCache.getIterator();

                            while ( itr.hasNext() )
                            {
                                Map.Entry entry = ( Map.Entry ) itr.next();
                                Serializable key = ( Serializable ) entry.getKey();
                                MemoryElementDescriptor me = ( MemoryElementDescriptor ) entry.getValue();
                                try
                                {
                                    if ( aux.getCacheType() == ICacheType.LATERAL_CACHE && !me.ce.getElementAttributes().getIsLateral() )
                                    {
                                        continue;
                                    }
                                    aux.put( key, me.ce.getVal(), me.ce.getElementAttributes() );
                                }
                                catch ( Exception e )
                                {
                                    log.error( e );
                                }
                            }
                        }
                        if ( aux.getCacheType() == ICache.DISK_CACHE )
                        {
                            aux.dispose();
                        }
                    }
                }
                catch ( IOException ex )
                {
                    handleException( ex );
                }
            }
        }

        log.warn( "Called close for " + cacheName );

    }


    /**
     * Though this put is extremely fast, this could bog the cache and should be
     * avoided. The dispose method should call a version of this. Good for
     * testing.
     */
    public void save()
    {
        if ( !alive )
        {
            return;
        }
        synchronized ( this )
        {
            if ( !alive )
            {
                return;
            }
            alive = false;

            for ( int i = 0; i < auxCaches.length; i++ )
            {
                try
                {
                    ICache aux = auxCaches[i];

                    if ( aux.getStatus() == ICache.STATUS_ALIVE )
                    {

                        Iterator itr = memCache.getIterator();

                        while ( itr.hasNext() )
                        {
                            Map.Entry entry = ( Map.Entry ) itr.next();
                            Serializable key = ( Serializable ) entry.getKey();
                            MemoryElementDescriptor me = ( MemoryElementDescriptor ) entry.getValue();
                            //try {
                            // should call update
                            aux.put( key, me.ce.getVal(), me.ce.getElementAttributes() );
                            // remove this exception from the interface
                            //} catch( Exception e ) {
                            //  log.error( e );
                            //}
                        }
                    }
                }
                catch ( IOException ex )
                {
                    handleException( ex );
                }
            }
        }
        if ( log.isDebugEnabled() )
        {
            log.debug( "Called save for " + cacheName );
        }
    }


    /**
     * Gets the stats attribute of the Cache object
     *
     * FIXME: Remove HTML!
     *
     * @return The stats value
     */
    public String getStats()
    {
        StringBuffer stats = new StringBuffer();
        stats.append( "cacheName = " + cacheName + ", numInstances = " + numInstances );
        stats.append( "<br> ramSize = " + memCache.getSize() + "/ ramHit = " + ramHit );

        for ( int i = 0; i < auxHit.length; i++ )
        {
            stats.append( "/n<br> auxHit[" + i + "] = " + auxHit[i] + ", " + this.auxCaches[i].getClass().getName() + "" );
        }
        stats.append( "/n<br> miss = " + miss );
        stats.append( "/n<br> cacheAttr = " + cacheAttr.toString() );
        return stats.toString();
    }


    /**
     * Gets the size attribute of the Cache object
     *
     * @return The size value
     */
    public int getSize()
    {
        return memCache.getSize();
    }


    /**
     * Gets the cacheType attribute of the Cache object
     *
     * @return The cacheType value
     */
    public int getCacheType()
    {
        return COMPOSITE_CACHE;
    }


    /**
     * Gets the status attribute of the Cache object
     *
     * @return The status value
     */
    public int getStatus()
    {
        return alive ? STATUS_ALIVE : STATUS_DISPOSED;
    }


    /**
     * Description of the Method
     *
     * @param ex
     */
    private void handleException( IOException ex )
    {
        ex.printStackTrace();
    }


    /**
     * Gets the cacheName attribute of the Cache object
     *
     * @return The cacheName value
     */
    public String getCacheName()
    {
        return cacheName;
    }


    /**
     * Gets the default element attribute of the Cache object
     *
     * @return The attributes value
     */
    public IElementAttributes getElementAttributes()
    {
        return attr;
    }


    /**
     * Gets the ICompositeCacheAttributes attribute of the Cache object
     *
     * @return The ICompositeCacheAttributes value
     */
    public ICompositeCacheAttributes getCacheAttributes()
    {
        return this.cacheAttr;
    }

    /**
     * Sets the ICompositeCacheAttributes attribute of the Cache object
     *
     * @param cattr The new ICompositeCacheAttributes value
     */
    public void setCacheAttributes( ICompositeCacheAttributes cattr )
    {
        this.cacheAttr = cattr;
        // need a better way to do this, what if it is in error
        this.memCache.initialize( cattr.getCacheName(), cattr, this );
    }

    /**
     * Gets the elementAttributes attribute of the Cache object
     *
     * @return The elementAttributes value
     * @param key
     * @exception CacheException
     * @exception IOException
     */
    public IElementAttributes getElementAttributes( Serializable key )
        throws CacheException, IOException
    {
        CacheElement ce = ( CacheElement ) getCacheElement( key );
        if ( ce == null )
        {
            throw new ObjectNotFoundException( "key " + key + " is not found" );
        }
        return ce.getElementAttributes();
    }


    /**
     * Create the MemoryCache based on the config parameters. TODO: consider
     * making this an auxiliary, despite its close tie to the CacheHub. TODO:
     * might want to create a memory cache config file separate from that of the
     * hub -- ICompositeCacheAttributes
     *
     * @return
     * @param cattr
     */
    private IMemoryCache createMemoryCache( ICompositeCacheAttributes cattr )
    {
        // Create memory Cache
        if ( memCache == null )
        {
            try
            {
                Class c = Class.forName( cattr.getMemoryCacheName() );
                this.memCache = ( IMemoryCache ) c.newInstance();
                this.memCache.initialize( cacheName, cattr, ( ICacheHub ) this );
            }
            catch ( Exception e )
            {
                log.error( e );
                log.warn( "Using default memory cache" );
                this.memCache = ( IMemoryCache ) new LRUMemoryCache( cacheName, cattr, ( ICacheHub ) this );
                this.memCache.initialize( cacheName, cattr, ( ICacheHub ) this );
            }
        }
        else
        {
            log.warn( "Trying to create a memory cache after it already exists." );
        }
        return memCache;
    }
    // end createMemoryCache


}
TOP

Related Classes of org.apache.stratum.jcs.engine.control.Cache

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.