View Javadoc
1   package org.apache.commons.jcs3.access;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.IOException;
23  import java.util.HashMap;
24  import java.util.Map;
25  import java.util.Map.Entry;
26  import java.util.Set;
27  import java.util.function.Supplier;
28  import java.util.stream.Collectors;
29  
30  import org.apache.commons.jcs3.access.behavior.ICacheAccess;
31  import org.apache.commons.jcs3.access.exception.CacheException;
32  import org.apache.commons.jcs3.access.exception.InvalidArgumentException;
33  import org.apache.commons.jcs3.access.exception.InvalidHandleException;
34  import org.apache.commons.jcs3.access.exception.ObjectExistsException;
35  import org.apache.commons.jcs3.engine.CacheElement;
36  import org.apache.commons.jcs3.engine.behavior.ICacheElement;
37  import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
38  import org.apache.commons.jcs3.engine.control.CompositeCache;
39  
40  /**
41   * This class provides an interface for all types of access to the cache.
42   * <p>
43   * An instance of this class is tied to a specific cache region. Static methods are provided to get
44   * such instances.
45   * <p>
46   * Using this class you can retrieve an item, the item's wrapper, and the element's configuration.  You can also put an
47   * item in the cache, remove an item, and clear a region.
48   * <p>
49   * The JCS class is the preferred way to access these methods.
50   */
51  public class CacheAccess<K, V>
52      extends AbstractCacheAccess<K, V>
53      implements ICacheAccess<K, V>
54  {
55      /**
56       * Constructor for the CacheAccess object.
57       * <p>
58       * @param cacheControl The cache which the created instance accesses
59       */
60      public CacheAccess( final CompositeCache<K, V> cacheControl )
61      {
62          super(cacheControl);
63      }
64  
65      /**
66       * Retrieve an object from the cache region this instance provides access to.
67       * <p>
68       * @param name Key the object is stored as
69       * @return The object if found or null
70       */
71      @Override
72      public V get( final K name )
73      {
74          final ICacheElement<K, V> element = this.getCacheControl().get( name );
75  
76          return ( element != null ) ? element.getVal() : null;
77      }
78  
79      /**
80       * Retrieve an object from the cache region this instance provides access to.
81       * If the object cannot be found in the cache, it will be retrieved by
82       * calling the supplier and subsequently storing it in the cache.
83       * <p>
84       * @param name
85       * @param supplier supplier to be called if the value is not found
86       * @return Object.
87       */
88      @Override
89      public V get(final K name, final Supplier<V> supplier)
90      {
91          V value = get(name);
92  
93          if (value == null)
94          {
95              value = supplier.get();
96              put(name, value);
97          }
98  
99          return value;
100     }
101 
102     /**
103      * Retrieve matching objects from the cache region this instance provides access to.
104      * <p>
105      * @param pattern - a key pattern for the objects stored
106      * @return A map of key to values.  These are stripped from the wrapper.
107      */
108     @Override
109     public Map<K, V> getMatching( final String pattern )
110     {
111         final Map<K, V> unwrappedResults;
112 
113         final Map<K, ICacheElement<K, V>> wrappedResults = this.getCacheControl().getMatching( pattern );
114 
115         if ( wrappedResults == null )
116         {
117             unwrappedResults = new HashMap<>();
118         }
119         else
120         {
121             unwrappedResults = wrappedResults.entrySet()
122                     .stream()
123                     .filter(entry -> entry.getValue() != null)
124                     .collect(Collectors.toMap(
125                             Entry::getKey,
126                             entry -> entry.getValue().getVal()));
127         }
128 
129         return unwrappedResults;
130     }
131 
132     /**
133      * This method returns the ICacheElement&lt;K, V&gt; wrapper which provides access to element info and other
134      * attributes.
135      * <p>
136      * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
137      * defensive copy is made.
138      * <p>
139      * This method is most useful if you want to determine things such as the how long the element
140      * has been in the cache.
141      * <p>
142      * The last access time in the ElementAttributes should be current.
143      * <p>
144      * @param name Key the Serializable is stored as
145      * @return The ICacheElement&lt;K, V&gt; if the object is found or null
146      */
147     @Override
148     public ICacheElement<K, V> getCacheElement( final K name )
149     {
150         return this.getCacheControl().get( name );
151     }
152 
153     /**
154      * Get multiple elements from the cache based on a set of cache keys.
155      * <p>
156      * This method returns the ICacheElement&lt;K, V&gt; wrapper which provides access to element info and other
157      * attributes.
158      * <p>
159      * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
160      * defensive copy is made.
161      * <p>
162      * This method is most useful if you want to determine things such as the how long the element
163      * has been in the cache.
164      * <p>
165      * The last access time in the ElementAttributes should be current.
166      * <p>
167      * @param names set of Serializable cache keys
168      * @return a map of K key to ICacheElement&lt;K, V&gt; element, or empty map if none of the keys are present
169      */
170     @Override
171     public Map<K, ICacheElement<K, V>> getCacheElements( final Set<K> names )
172     {
173         return this.getCacheControl().getMultiple( names );
174     }
175 
176     /**
177      * Get multiple elements from the cache based on a set of cache keys.
178      * <p>
179      * This method returns the ICacheElement&lt;K, V&gt; wrapper which provides access to element info and other
180      * attributes.
181      * <p>
182      * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
183      * defensive copy is made.
184      * <p>
185      * This method is most useful if you want to determine things such as the how long the element
186      * has been in the cache.
187      * <p>
188      * The last access time in the ElementAttributes should be current.
189      * <p>
190      * @param pattern key search pattern
191      * @return a map of K key to ICacheElement&lt;K, V&gt; element, or empty map if no keys match the pattern
192      */
193     @Override
194     public Map<K, ICacheElement<K, V>> getMatchingCacheElements( final String pattern )
195     {
196         return this.getCacheControl().getMatching( pattern );
197     }
198 
199     /**
200      * Place a new object in the cache, associated with key name. If there is currently an object
201      * associated with name in the region an ObjectExistsException is thrown. Names are scoped to a
202      * region so they must be unique within the region they are placed.
203      * <p>
204      * @param key Key object will be stored with
205      * @param value Object to store
206      * @throws CacheException and ObjectExistsException is thrown if the item is already in the
207      *                cache.
208      */
209     @Override
210     public void putSafe( final K key, final V value )
211     {
212         if ( this.getCacheControl().get( key ) != null )
213         {
214             throw new ObjectExistsException( "putSafe failed.  Object exists in the cache for key [" + key
215                 + "].  Remove first or use a non-safe put to override the value." );
216         }
217         put( key, value );
218     }
219 
220     /**
221      * Place a new object in the cache, associated with key name. If there is currently an object
222      * associated with name in the region it is replaced. Names are scoped to a region so they must
223      * be unique within the region they are placed.
224      * @param name Key object will be stored with
225      * @param obj Object to store
226      */
227     @Override
228     public void put( final K name, final V obj )
229     {
230         // Call put with a copy of the contained caches default attributes.
231         // the attributes are copied by the cacheControl
232         put( name, obj, this.getCacheControl().getElementAttributes() );
233     }
234 
235     /**
236      * Constructs a cache element with these attributes, and puts it into the cache.
237      * <p>
238      * If the key or the value is null, and InvalidArgumentException is thrown.
239      * <p>
240      * @see org.apache.commons.jcs3.access.behavior.ICacheAccess#put(Object, Object, IElementAttributes)
241      */
242     @Override
243     public void put( final K key, final V val, final IElementAttributes attr )
244     {
245         if ( key == null )
246         {
247             throw new InvalidArgumentException( "Key must not be null" );
248         }
249 
250         if ( val == null )
251         {
252             throw new InvalidArgumentException( "Value must not be null" );
253         }
254 
255         // Create the element and update. This may throw an IOException which
256         // should be wrapped by cache access.
257         try
258         {
259             final CacheElement<K, V> ce = new CacheElement<>( this.getCacheControl().getCacheName(), key,
260                                                 val );
261 
262             ce.setElementAttributes( attr );
263 
264             this.getCacheControl().update( ce );
265         }
266         catch ( final IOException e )
267         {
268             throw new CacheException( e );
269         }
270     }
271 
272     /**
273      * Removes a single item by name.
274      * <p>
275      * @param name the name of the item to remove.
276      */
277     @Override
278     public void remove( final K name )
279     {
280         this.getCacheControl().remove( name );
281     }
282 
283     /**
284      * Reset attributes for a particular element in the cache. NOTE: this method is currently not
285      * implemented.
286      * <p>
287      * @param name Key of object to reset attributes for
288      * @param attr New attributes for the object
289      * @throws InvalidHandleException if the item does not exist.
290      */
291     @Override
292     public void resetElementAttributes( final K name, final IElementAttributes attr )
293     {
294         final ICacheElement<K, V> element = this.getCacheControl().get( name );
295 
296         if ( element == null )
297         {
298             throw new InvalidHandleException( "Object for name [" + name + "] is not in the cache" );
299         }
300 
301         // Although it will work currently, don't assume pass by reference here,
302         // i.e. don't do this:
303         // element.setElementAttributes( attr );
304         // Another reason to call put is to force the changes to be distributed.
305 
306         put( element.getKey(), element.getVal(), attr );
307     }
308 
309     /**
310      * GetElementAttributes will return an attribute object describing the current attributes
311      * associated with the object name. The name object must override the Object.equals and
312      * Object.hashCode methods.
313      * <p>
314      * @param name Key of object to get attributes for
315      * @return Attributes for the object, null if object not in cache
316      */
317     @Override
318     public IElementAttributes getElementAttributes( final K name ) throws CacheException
319     {
320         IElementAttributes attr = null;
321 
322         try
323         {
324             attr = this.getCacheControl().getElementAttributes( name );
325         }
326         catch ( final IOException ioe )
327         {
328             throw new CacheException("Failure getting element attributes", ioe);
329         }
330 
331         return attr;
332     }
333 }