001package org.apache.commons.jcs.access;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.IOException;
023import java.util.HashMap;
024import java.util.Map;
025import java.util.Set;
026
027import org.apache.commons.jcs.access.behavior.ICacheAccess;
028import org.apache.commons.jcs.access.exception.CacheException;
029import org.apache.commons.jcs.access.exception.InvalidArgumentException;
030import org.apache.commons.jcs.access.exception.InvalidHandleException;
031import org.apache.commons.jcs.access.exception.ObjectExistsException;
032import org.apache.commons.jcs.engine.CacheElement;
033import org.apache.commons.jcs.engine.behavior.ICacheElement;
034import org.apache.commons.jcs.engine.behavior.IElementAttributes;
035import org.apache.commons.jcs.engine.control.CompositeCache;
036import org.apache.commons.logging.Log;
037import org.apache.commons.logging.LogFactory;
038
039/**
040 * This class provides an interface for all types of access to the cache.
041 * <p>
042 * An instance of this class is tied to a specific cache region. Static methods are provided to get
043 * such instances.
044 * <p>
045 * Using this class you can retrieve an item, the item's wrapper, and the element's configuration.  You can also put an
046 * item in the cache, remove an item, and clear a region.
047 * <p>
048 * The JCS class is the preferred way to access these methods.
049 */
050public class CacheAccess<K, V>
051    extends AbstractCacheAccess<K, V>
052    implements ICacheAccess<K, V>
053{
054    /** The logger. */
055    private static final Log log = LogFactory.getLog( CacheAccess.class );
056
057    /**
058     * Constructor for the CacheAccess object.
059     * <p>
060     * @param cacheControl The cache which the created instance accesses
061     */
062    public CacheAccess( CompositeCache<K, V> cacheControl )
063    {
064        super(cacheControl);
065    }
066
067    /**
068     * Retrieve an object from the cache region this instance provides access to.
069     * <p>
070     * @param name Key the object is stored as
071     * @return The object if found or null
072     */
073    @Override
074    public V get( K name )
075    {
076        ICacheElement<K, V> element = this.getCacheControl().get( name );
077
078        return ( element != null ) ? element.getVal() : null;
079    }
080
081    /**
082     * Retrieve matching objects from the cache region this instance provides access to.
083     * <p>
084     * @param pattern - a key pattern for the objects stored
085     * @return A map of key to values.  These are stripped from the wrapper.
086     */
087    @Override
088    public Map<K, V> getMatching( String pattern )
089    {
090        HashMap<K, V> unwrappedResults = new HashMap<K, V>();
091
092        Map<K, ICacheElement<K, V>> wrappedResults = this.getCacheControl().getMatching( pattern );
093        if ( wrappedResults != null )
094        {
095            for (Map.Entry<K, ICacheElement<K, V>> entry : wrappedResults.entrySet())
096            {
097                ICacheElement<K, V> element = entry.getValue();
098                if ( element != null )
099                {
100                    unwrappedResults.put( entry.getKey(), element.getVal() );
101                }
102            }
103        }
104        return unwrappedResults;
105    }
106
107    /**
108     * This method returns the ICacheElement&lt;K, V&gt; wrapper which provides access to element info and other
109     * attributes.
110     * <p>
111     * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
112     * defensive copy is made.
113     * <p>
114     * This method is most useful if you want to determine things such as the how long the element
115     * has been in the cache.
116     * <p>
117     * The last access time in the ElementAttributes should be current.
118     * <p>
119     * @param name Key the Serializable is stored as
120     * @return The ICacheElement&lt;K, V&gt; if the object is found or null
121     */
122    @Override
123    public ICacheElement<K, V> getCacheElement( K name )
124    {
125        return this.getCacheControl().get( name );
126    }
127
128    /**
129     * Get multiple elements from the cache based on a set of cache keys.
130     * <p>
131     * This method returns the ICacheElement&lt;K, V&gt; wrapper which provides access to element info and other
132     * attributes.
133     * <p>
134     * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
135     * defensive copy is made.
136     * <p>
137     * This method is most useful if you want to determine things such as the how long the element
138     * has been in the cache.
139     * <p>
140     * The last access time in the ElementAttributes should be current.
141     * <p>
142     * @param names set of Serializable cache keys
143     * @return a map of K key to ICacheElement&lt;K, V&gt; element, or empty map if none of the keys are present
144     */
145    @Override
146    public Map<K, ICacheElement<K, V>> getCacheElements( Set<K> names )
147    {
148        return this.getCacheControl().getMultiple( names );
149    }
150
151    /**
152     * Get multiple elements from the cache based on a set of cache keys.
153     * <p>
154     * This method returns the ICacheElement&lt;K, V&gt; wrapper which provides access to element info and other
155     * attributes.
156     * <p>
157     * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
158     * defensive copy is made.
159     * <p>
160     * This method is most useful if you want to determine things such as the how long the element
161     * has been in the cache.
162     * <p>
163     * The last access time in the ElementAttributes should be current.
164     * <p>
165     * @param pattern key search pattern
166     * @return a map of K key to ICacheElement&lt;K, V&gt; element, or empty map if no keys match the pattern
167     */
168    @Override
169    public Map<K, ICacheElement<K, V>> getMatchingCacheElements( String pattern )
170    {
171        return this.getCacheControl().getMatching( pattern );
172    }
173
174    /**
175     * Place a new object in the cache, associated with key name. If there is currently an object
176     * associated with name in the region an ObjectExistsException is thrown. Names are scoped to a
177     * region so they must be unique within the region they are placed.
178     * <p>
179     * @param key Key object will be stored with
180     * @param value Object to store
181     * @throws CacheException and ObjectExistsException is thrown if the item is already in the
182     *                cache.
183     */
184    @Override
185    public void putSafe( K key, V value )
186    {
187        if ( this.getCacheControl().get( key ) != null )
188        {
189            throw new ObjectExistsException( "putSafe failed.  Object exists in the cache for key [" + key
190                + "].  Remove first or use a non-safe put to override the value." );
191        }
192        put( key, value );
193    }
194
195    /**
196     * Place a new object in the cache, associated with key name. If there is currently an object
197     * associated with name in the region it is replaced. Names are scoped to a region so they must
198     * be unique within the region they are placed.
199     * @param name Key object will be stored with
200     * @param obj Object to store
201     */
202    @Override
203    public void put( K name, V obj )
204    {
205        // Call put with a copy of the contained caches default attributes.
206        // the attributes are copied by the cacheControl
207        put( name, obj, this.getCacheControl().getElementAttributes() );
208    }
209
210    /**
211     * Constructs a cache element with these attributes, and puts it into the cache.
212     * <p>
213     * If the key or the value is null, and InvalidArgumentException is thrown.
214     * <p>
215     * @see org.apache.commons.jcs.access.behavior.ICacheAccess#put(Object, Object, IElementAttributes)
216     */
217    @Override
218    public void put( K key, V val, IElementAttributes attr )
219    {
220        if ( key == null )
221        {
222            throw new InvalidArgumentException( "Key must not be null" );
223        }
224
225        if ( val == null )
226        {
227            throw new InvalidArgumentException( "Value must not be null" );
228        }
229
230        // Create the element and update. This may throw an IOException which
231        // should be wrapped by cache access.
232        try
233        {
234            CacheElement<K, V> ce = new CacheElement<K, V>( this.getCacheControl().getCacheName(), key,
235                                                val );
236
237            ce.setElementAttributes( attr );
238
239            this.getCacheControl().update( ce );
240        }
241        catch ( IOException e )
242        {
243            throw new CacheException( e );
244        }
245    }
246
247    /**
248     * Removes a single item by name.
249     * <p>
250     * @param name the name of the item to remove.
251     */
252    @Override
253    public void remove( K name )
254    {
255        this.getCacheControl().remove( name );
256    }
257
258    /**
259     * Reset attributes for a particular element in the cache. NOTE: this method is currently not
260     * implemented.
261     * <p>
262     * @param name Key of object to reset attributes for
263     * @param attr New attributes for the object
264     * @throws InvalidHandleException if the item does not exist.
265     */
266    @Override
267    public void resetElementAttributes( K name, IElementAttributes attr )
268    {
269        ICacheElement<K, V> element = this.getCacheControl().get( name );
270
271        if ( element == null )
272        {
273            throw new InvalidHandleException( "Object for name [" + name + "] is not in the cache" );
274        }
275
276        // Although it will work currently, don't assume pass by reference here,
277        // i.e. don't do this:
278        // element.setElementAttributes( attr );
279        // Another reason to call put is to force the changes to be distributed.
280
281        put( element.getKey(), element.getVal(), attr );
282    }
283
284    /**
285     * GetElementAttributes will return an attribute object describing the current attributes
286     * associated with the object name. The name object must override the Object.equals and
287     * Object.hashCode methods.
288     * <p>
289     * @param name Key of object to get attributes for
290     * @return Attributes for the object, null if object not in cache
291     */
292    @Override
293    public IElementAttributes getElementAttributes( K name )
294    {
295        IElementAttributes attr = null;
296
297        try
298        {
299            attr = this.getCacheControl().getElementAttributes( name );
300        }
301        catch ( IOException ioe )
302        {
303            log.error( "Failure getting element attributes", ioe );
304        }
305
306        return attr;
307    }
308}