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<K, V> 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<K, V> 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<K, V> 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<K, V> 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<K, V> 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<K, V> 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 }