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
}