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 }