blob: 459a06116856ee9e17d06302425287d6a14c244a [file] [log] [blame]
package org.apache.jcs.access;
/*
* 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.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jcs.access.behavior.ICacheAccess;
import org.apache.jcs.access.exception.CacheException;
import org.apache.jcs.access.exception.InvalidArgumentException;
import org.apache.jcs.access.exception.InvalidHandleException;
import org.apache.jcs.access.exception.ObjectExistsException;
import org.apache.jcs.engine.CacheElement;
import org.apache.jcs.engine.behavior.ICacheElement;
import org.apache.jcs.engine.behavior.ICompositeCacheAttributes;
import org.apache.jcs.engine.behavior.IElementAttributes;
import org.apache.jcs.engine.control.CompositeCache;
import org.apache.jcs.engine.control.CompositeCacheManager;
import org.apache.jcs.engine.stats.behavior.ICacheStats;
/**
* This class provides an interface for all types of access to the cache.
* <p>
* An instance of this class is tied to a specific cache region. Static methods are provided to get
* such instances.
* <p>
* Using this class you can retrieve an item, the item's wrapper, and the element's configuration. You can also put an
* item in the cache, remove an item, and clear a region.
* <p>
* The JCS class is the preferred way to access these methods.
*/
public class CacheAccess
implements ICacheAccess
{
/** The logger. */
private static final Log log = LogFactory.getLog( CacheAccess.class );
/** Cache manager use by the various forms of defineRegion and getAccess */
private static CompositeCacheManager cacheMgr;
/**
* The cache that a given instance of this class provides access to.
* <p>
* @TODO Should this be the interface?
*/
protected CompositeCache cacheControl;
/**
* Constructor for the CacheAccess object.
* <p>
* @param cacheControl The cache which the created instance accesses
*/
public CacheAccess( CompositeCache cacheControl )
{
this.cacheControl = cacheControl;
}
// ----------------------------- static methods for access to cache regions
/**
* Define a new cache region with the given name. In the oracle specification, these attributes
* are global and not region specific, regional overrides is a value add each region should be
* able to house both cache and element attribute sets. It is more efficient to define a cache
* in the props file and then strictly use the get access method. Use of the define region
* outside of an initialization block should be avoided.
* <p>
* @param name Name that will identify the region
* @return CacheAccess instance for the new region
* @exception CacheException
*/
public static CacheAccess defineRegion( String name )
throws CacheException
{
ensureCacheManager();
return new CacheAccess( cacheMgr.getCache( name ) );
}
/**
* Define a new cache region with the specified name and attributes.
* <p>
* @param name Name that will identify the region
* @param cattr CompositeCacheAttributes for the region
* @return CacheAccess instance for the new region
* @exception CacheException
*/
public static CacheAccess defineRegion( String name, ICompositeCacheAttributes cattr )
throws CacheException
{
ensureCacheManager();
return new CacheAccess( cacheMgr.getCache( name, cattr ) );
}
/**
* Define a new cache region with the specified name and attributes and return a CacheAccess to
* it.
* <p>
* @param name Name that will identify the region
* @param cattr CompositeCacheAttributes for the region
* @param attr Attributes for the region
* @return CacheAccess instance for the new region
* @exception CacheException
*/
public static CacheAccess defineRegion( String name, ICompositeCacheAttributes cattr, IElementAttributes attr )
throws CacheException
{
ensureCacheManager();
return new CacheAccess( cacheMgr.getCache( name, cattr, attr ) );
}
/**
* Get a CacheAccess instance for the given region.
* <p>
* @param region Name that identifies the region
* @return CacheAccess instance for region
* @exception CacheException
*/
public static CacheAccess getAccess( String region )
throws CacheException
{
ensureCacheManager();
return new CacheAccess( cacheMgr.getCache( region ) );
}
/**
* Get a CacheAccess instance for the given region with the given attributes.
* <p>
* @param region Name that identifies the region
* @param icca
* @return CacheAccess instance for region
* @exception CacheException
*/
public static CacheAccess getAccess( String region, ICompositeCacheAttributes icca )
throws CacheException
{
ensureCacheManager();
return new CacheAccess( cacheMgr.getCache( region, icca ) );
}
/**
* Helper method which checks to make sure the cacheMgr class field is set, and if not requests
* an instance from CacheManagerFactory.
*/
protected static void ensureCacheManager()
{
synchronized ( CacheAccess.class )
{
if ( cacheMgr == null )
{
cacheMgr = CompositeCacheManager.getInstance();
}
}
}
// ------------------------------------------------------- instance methods
/**
* Retrieve an object from the cache region this instance provides access to.
* <p>
* @param name Key the object is stored as
* @return The object if found or null
*/
public Object get( Object name )
{
ICacheElement element = this.cacheControl.get( (Serializable) name );
return ( element != null ) ? element.getVal() : null;
}
/**
* Retrieve matching objects from the cache region this instance provides access to.
* <p>
* @param pattern - a key pattern for the objects stored
* @return A map of key to values. These are stripped from the wrapper.
*/
public HashMap getMatching( String pattern )
{
HashMap unwrappedResults = new HashMap();
Map wrappedResults = this.cacheControl.getMatching( pattern );
if ( wrappedResults != null )
{
Set keySet = wrappedResults.keySet();
Iterator it = keySet.iterator();
while ( it.hasNext() )
{
Object key = it.next();
ICacheElement element = (ICacheElement)wrappedResults.get( key );
if ( element != null )
{
unwrappedResults.put( key, element.getVal() );
}
}
}
return unwrappedResults;
}
/**
* This method returns the ICacheElement wrapper which provides access to element info and other
* attributes.
* <p>
* This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
* defensive copy is made.
* <p>
* This method is most useful if you want to determine things such as the how long the element
* has been in the cache.
* <p>
* The last access time in the ElementAttributes should be current.
* <p>
* @param name Key the object is stored as
* @return The ICacheElement if the object is found or null
*/
public ICacheElement getCacheElement( Object name )
{
return this.cacheControl.get( (Serializable) name );
}
/**
* Get multiple elements from the cache based on a set of cache keys.
* <p>
* This method returns the ICacheElement wrapper which provides access to element info and other
* attributes.
* <p>
* This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
* defensive copy is made.
* <p>
* This method is most useful if you want to determine things such as the how long the element
* has been in the cache.
* <p>
* The last access time in the ElementAttributes should be current.
* <p>
* @param names set of Object cache keys
* @return a map of Object key to ICacheElement element, or empty map if none of the keys are present
*/
public Map getCacheElements( Set names )
{
return this.cacheControl.getMultiple( names );
}
/**
* Get multiple elements from the cache based on a set of cache keys.
* <p>
* This method returns the ICacheElement wrapper which provides access to element info and other
* attributes.
* <p>
* This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
* defensive copy is made.
* <p>
* This method is most useful if you want to determine things such as the how long the element
* has been in the cache.
* <p>
* The last access time in the ElementAttributes should be current.
* <p>
* @param pattern key search pattern
* @return a map of Object key to ICacheElement element, or empty map if no keys match the pattern
*/
public Map getMatchingCacheElements( String pattern )
{
return this.cacheControl.getMatching( pattern );
}
/**
* Place a new object in the cache, associated with key name. If there is currently an object
* associated with name in the region an ObjectExistsException is thrown. Names are scoped to a
* region so they must be unique within the region they are placed.
* <p>
* @param key Key object will be stored with
* @param value Object to store
* @exception CacheException and ObjectExistsException is thrown if the item is already in the
* cache.
*/
public void putSafe( Object key, Object value )
throws CacheException
{
if ( this.cacheControl.get( (Serializable) key ) != null )
{
throw new ObjectExistsException( "putSafe failed. Object exists in the cache for key [" + key
+ "]. Remove first or use a non-safe put to override the value." );
}
put( key, value );
}
/**
* Place a new object in the cache, associated with key name. If there is currently an object
* associated with name in the region it is replaced. Names are scoped to a region so they must
* be unique within the region they are placed. ObjectExistsException
* @param name Key object will be stored with
* @param obj Object to store
* @exception CacheException
*/
public void put( Object name, Object obj )
throws CacheException
{
// Call put with a copy of the contained caches default attributes.
// the attributes are copied by the cacheControl
put( name, obj, this.cacheControl.getElementAttributes() );
}
/**
* Constructs a cache element with these attributes, and puts it into the cache.
* <p>
* If the key or the value is null, and InvalidArgumentException is thrown.
* <p>
* @see org.apache.jcs.access.behavior.ICacheAccess#put(java.lang.Object, java.lang.Object,
* org.apache.jcs.engine.behavior.IElementAttributes)
*/
public void put( Object key, Object val, IElementAttributes attr )
throws CacheException
{
if ( key == null )
{
throw new InvalidArgumentException( "Key must not be null" );
}
else if ( val == null )
{
throw new InvalidArgumentException( "Value must not be null" );
}
// Create the element and update. This may throw an IOException which
// should be wrapped by cache access.
try
{
CacheElement ce = new CacheElement( this.cacheControl.getCacheName(), (Serializable) key,
(Serializable) val );
ce.setElementAttributes( attr );
this.cacheControl.update( ce );
}
catch ( Exception e )
{
throw new CacheException( e );
}
}
/**
* Destroy the region and all objects within it. After calling this method, the Cache object can
* no longer be used as it will be closed.
* <p>
* @exception CacheException
* @deprecated
*/
public void destroy()
throws CacheException
{
try
{
this.cacheControl.removeAll();
}
catch ( IOException e )
{
throw new CacheException( e );
}
}
/**
* Removes all of the elements from a region.
* <p>
* @deprecated use clear()
* @throws CacheException
*/
public void remove()
throws CacheException
{
clear();
}
/**
* Removes all of the elements from a region.
* <p>
* @throws CacheException
*/
public void clear()
throws CacheException
{
try
{
this.cacheControl.removeAll();
}
catch ( IOException e )
{
throw new CacheException( e );
}
}
/**
* Invalidate all objects associated with key name, removing all references to the objects from
* the cache.
* <p>
* @param name Key that specifies object to invalidate
* @exception CacheException
* @deprecated use remove
*/
public void destroy( Object name )
throws CacheException
{
this.cacheControl.remove( (Serializable) name );
}
/**
* Removes a single item by name.
* <p>
* @param name the name of the item to remove.
* @throws CacheException
*/
public void remove( Object name )
throws CacheException
{
this.cacheControl.remove( (Serializable) name );
}
/**
* ResetAttributes allows for some of the attributes of a region to be reset in particular
* expiration time attributes, time to live, default time to live and idle time, and event
* handlers. Changing default settings on groups and regions will not affect existing objects.
* Only object loaded after the reset will use the new defaults. If no name argument is
* provided, the reset is applied to the region.
* <p>
* NOTE: this method is does not reset the attributes for items already in the cache. It could
* potentially do this for items in memory, and maybe on disk (which would be slow) but not
* remote items. Rather than have unpredictable behavior, this method just sets the default
* attributes.
* <p>
* TODO is should be renamed "setDefaultElementAttributes"
* <p>
* @deprecated As of release 1.3
* @see #setDefaultElementAttributes(IElementAttributes)
* @param attr New attributes for this region.
* @exception CacheException
* @exception InvalidHandleException
*/
public void resetElementAttributes( IElementAttributes attr )
throws CacheException, InvalidHandleException
{
this.cacheControl.setElementAttributes( attr );
}
/**
* This method is does not reset the attributes for items already in the cache. It could
* potentially do this for items in memory, and maybe on disk (which would be slow) but not
* remote items. Rather than have unpredictable behavior, this method just sets the default
* attributes. Items subsequently put into the cache will use these defaults if they do not
* specify specific attributes.
* <p>
* @param attr the default attributes.
* @throws CacheException if something goes wrong.
*/
public void setDefaultElementAttributes( IElementAttributes attr )
throws CacheException
{
this.cacheControl.setElementAttributes( attr );
}
/**
* Reset attributes for a particular element in the cache. NOTE: this method is currently not
* implemented.
* <p>
* @param name Key of object to reset attributes for
* @param attr New attributes for the object
* @exception CacheException
* @exception InvalidHandleException if the item does not exist.
*/
public void resetElementAttributes( Object name, IElementAttributes attr )
throws CacheException, InvalidHandleException
{
ICacheElement element = this.cacheControl.get( (Serializable) name );
if ( element == null )
{
throw new InvalidHandleException( "Object for name [" + name + "] is not in the cache" );
}
// Although it will work currently, don't assume pass by reference here,
// i.e. don't do this:
// element.setElementAttributes( attr );
// Another reason to call put is to force the changes to be distributed.
put( element.getKey(), element.getVal(), attr );
}
/**
* GetElementAttributes will return an attribute object describing the current attributes
* associated with the object name.
* <p>
* This was confusing, so I created a new method with a clear name.
* <p>
* @deprecated As of release 1.3
* @see #getDefaultElementAttributes
* @return Attributes for this region
* @exception CacheException
*/
public IElementAttributes getElementAttributes()
throws CacheException
{
return this.cacheControl.getElementAttributes();
}
/**
* Retrieves A COPY OF the default element attributes used by this region. This does not provide
* a reference to the element attributes.
* <p>
* Each time an element is added to the cache without element attributes, the default element
* attributes are cloned.
* <p>
* @return the deafualt element attributes used by this region.
* @throws CacheException
*/
public IElementAttributes getDefaultElementAttributes()
throws CacheException
{
return this.cacheControl.getElementAttributes();
}
/**
* GetElementAttributes will return an attribute object describing the current attributes
* associated with the object name. The name object must override the Object.equals and
* Object.hashCode methods.
* <p>
* @param name Key of object to get attributes for
* @return Attributes for the object, null if object not in cache
* @exception CacheException
*/
public IElementAttributes getElementAttributes( Object name )
throws CacheException
{
IElementAttributes attr = null;
try
{
attr = this.cacheControl.getElementAttributes( (Serializable) name );
}
catch ( IOException ioe )
{
log.error( "Failure getting element attributes", ioe );
}
return attr;
}
/**
* This returns the ICacheStats object with information on this region and its auxiliaries.
* <p>
* This data can be formatted as needed.
* <p>
* @return ICacheStats
*/
public ICacheStats getStatistics()
{
return this.cacheControl.getStatistics();
}
/**
* @return A String version of the stats.
*/
public String getStats()
{
return this.cacheControl.getStats();
}
/**
* Dispose this region. Flushes objects to and closes auxiliary caches. This is a shutdown
* command!
* <p>
* To simply remove all elements from the region use clear().
*/
public void dispose()
{
this.cacheControl.dispose();
}
/**
* Gets the ICompositeCacheAttributes of the cache region.
* <p>
* @return ICompositeCacheAttributes, the controllers config info, defined in the top section of
* a region definition.
*/
public ICompositeCacheAttributes getCacheAttributes()
{
return this.cacheControl.getCacheAttributes();
}
/**
* Sets the ICompositeCacheAttributes of the cache region.
* <p>
* @param cattr The new ICompositeCacheAttribute value
*/
public void setCacheAttributes( ICompositeCacheAttributes cattr )
{
this.cacheControl.setCacheAttributes( cattr );
}
/**
* This instructs the memory cache to remove the <i>numberToFree</i> according to its eviction
* policy. For example, the LRUMemoryCache will remove the <i>numberToFree</i> least recently
* used items. These will be spooled to disk if a disk auxiliary is available.
* <p>
* @param numberToFree
* @return the number that were removed. if you ask to free 5, but there are only 3, you will
* get 3.
* @throws CacheException
*/
public int freeMemoryElements( int numberToFree )
throws CacheException
{
int numFreed = -1;
try
{
numFreed = this.cacheControl.getMemoryCache().freeElements( numberToFree );
}
catch ( IOException ioe )
{
String message = "Failure freeing memory elements. ";
log.error( message, ioe );
throw new CacheException( message + ioe.getMessage() );
}
return numFreed;
}
}