001 package org.apache.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
022 import java.io.IOException;
023 import java.io.Serializable;
024 import java.util.HashMap;
025 import java.util.Map;
026 import java.util.Set;
027
028 import org.apache.commons.logging.Log;
029 import org.apache.commons.logging.LogFactory;
030 import org.apache.jcs.access.behavior.ICacheAccess;
031 import org.apache.jcs.access.exception.CacheException;
032 import org.apache.jcs.access.exception.InvalidArgumentException;
033 import org.apache.jcs.access.exception.InvalidHandleException;
034 import org.apache.jcs.access.exception.ObjectExistsException;
035 import org.apache.jcs.engine.CacheElement;
036 import org.apache.jcs.engine.behavior.ICacheElement;
037 import org.apache.jcs.engine.behavior.ICompositeCacheAttributes;
038 import org.apache.jcs.engine.behavior.IElementAttributes;
039 import org.apache.jcs.engine.control.CompositeCache;
040 import org.apache.jcs.engine.control.CompositeCacheManager;
041 import org.apache.jcs.engine.stats.behavior.ICacheStats;
042
043 /**
044 * This class provides an interface for all types of access to the cache.
045 * <p>
046 * An instance of this class is tied to a specific cache region. Static methods are provided to get
047 * such instances.
048 * <p>
049 * Using this class you can retrieve an item, the item's wrapper, and the element's configuration. You can also put an
050 * item in the cache, remove an item, and clear a region.
051 * <p>
052 * The JCS class is the preferred way to access these methods.
053 */
054 public class CacheAccess<K extends Serializable, V extends Serializable>
055 implements ICacheAccess<K, V>
056 {
057 /** The logger. */
058 private static final Log log = LogFactory.getLog( CacheAccess.class );
059
060 /** Cache manager use by the various forms of defineRegion and getAccess */
061 private static CompositeCacheManager cacheMgr;
062
063 /**
064 * The cache that a given instance of this class provides access to.
065 * <p>
066 * @TODO Should this be the interface?
067 */
068 protected CompositeCache<K, V> cacheControl;
069
070 /**
071 * Constructor for the CacheAccess object.
072 * <p>
073 * @param cacheControl The cache which the created instance accesses
074 */
075 public CacheAccess( CompositeCache<K, V> cacheControl )
076 {
077 this.cacheControl = cacheControl;
078 }
079
080 // ----------------------------- static methods for access to cache regions
081
082 /**
083 * Define a new cache region with the given name. In the oracle specification, these attributes
084 * are global and not region specific, regional overrides is a value add each region should be
085 * able to house both cache and element attribute sets. It is more efficient to define a cache
086 * in the props file and then strictly use the get access method. Use of the define region
087 * outside of an initialization block should be avoided.
088 * <p>
089 * @param name Name that will identify the region
090 * @return CacheAccess instance for the new region
091 * @exception CacheException
092 */
093 public static <K extends Serializable, V extends Serializable> CacheAccess<K, V> defineRegion( String name )
094 throws CacheException
095 {
096 CompositeCache<K, V> cache = getCacheManager().getCache( name );
097 return new CacheAccess<K, V>( cache );
098 }
099
100 /**
101 * Define a new cache region with the specified name and attributes.
102 * <p>
103 * @param name Name that will identify the region
104 * @param cattr CompositeCacheAttributes for the region
105 * @return CacheAccess instance for the new region
106 * @exception CacheException
107 */
108 public static <K extends Serializable, V extends Serializable> CacheAccess<K, V> defineRegion( String name, ICompositeCacheAttributes cattr )
109 throws CacheException
110 {
111 CompositeCache<K, V> cache = getCacheManager().getCache( name, cattr );
112 return new CacheAccess<K, V>( cache );
113 }
114
115 /**
116 * Define a new cache region with the specified name and attributes and return a CacheAccess to
117 * it.
118 * <p>
119 * @param name Name that will identify the region
120 * @param cattr CompositeCacheAttributes for the region
121 * @param attr Attributes for the region
122 * @return CacheAccess instance for the new region
123 * @exception CacheException
124 */
125 public static <K extends Serializable, V extends Serializable> CacheAccess<K, V> defineRegion( String name, ICompositeCacheAttributes cattr, IElementAttributes attr )
126 throws CacheException
127 {
128 CompositeCache<K, V> cache = getCacheManager().getCache( name, cattr, attr );
129 return new CacheAccess<K, V>( cache );
130 }
131
132 /**
133 * Get a CacheAccess instance for the given region.
134 * <p>
135 * @param region Name that identifies the region
136 * @return CacheAccess instance for region
137 * @exception CacheException
138 */
139 public static <K extends Serializable, V extends Serializable> CacheAccess<K, V> getAccess( String region )
140 throws CacheException
141 {
142 CompositeCache<K, V> cache = getCacheManager().getCache( region );
143 return new CacheAccess<K, V>( cache );
144 }
145
146 /**
147 * Get a CacheAccess instance for the given region with the given attributes.
148 * <p>
149 * @param region Name that identifies the region
150 * @param icca
151 * @return CacheAccess instance for region
152 * @exception CacheException
153 */
154 public static <K extends Serializable, V extends Serializable> CacheAccess<K, V> getAccess( String region, ICompositeCacheAttributes icca )
155 throws CacheException
156 {
157 CompositeCache<K, V> cache = getCacheManager().getCache( region, icca );
158 return new CacheAccess<K, V>( cache );
159 }
160
161 /**
162 * Helper method which checks to make sure the cacheMgr class field is set, and if not requests
163 * an instance from CacheManagerFactory.
164 *
165 * @throws CacheException if the configuration cannot be loaded
166 */
167 protected static CompositeCacheManager getCacheManager() throws CacheException
168 {
169 synchronized ( CacheAccess.class )
170 {
171 if ( cacheMgr == null )
172 {
173 cacheMgr = CompositeCacheManager.getInstance();
174 }
175
176 return cacheMgr;
177 }
178 }
179
180 // ------------------------------------------------------- instance methods
181
182 /**
183 * Retrieve an object from the cache region this instance provides access to.
184 * <p>
185 * @param name Key the object is stored as
186 * @return The object if found or null
187 */
188 public V get( K name )
189 {
190 ICacheElement<K, V> element = this.cacheControl.get( name );
191
192 return ( element != null ) ? element.getVal() : null;
193 }
194
195 /**
196 * Retrieve matching objects from the cache region this instance provides access to.
197 * <p>
198 * @param pattern - a key pattern for the objects stored
199 * @return A map of key to values. These are stripped from the wrapper.
200 */
201 public Map<K, V> getMatching( String pattern )
202 {
203 HashMap<K, V> unwrappedResults = new HashMap<K, V>();
204
205 Map<K, ICacheElement<K, V>> wrappedResults = this.cacheControl.getMatching( pattern );
206 if ( wrappedResults != null )
207 {
208 for (Map.Entry<K, ICacheElement<K, V>> entry : wrappedResults.entrySet())
209 {
210 ICacheElement<K, V> element = entry.getValue();
211 if ( element != null )
212 {
213 unwrappedResults.put( entry.getKey(), element.getVal() );
214 }
215 }
216 }
217 return unwrappedResults;
218 }
219
220 /**
221 * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
222 * attributes.
223 * <p>
224 * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
225 * defensive copy is made.
226 * <p>
227 * This method is most useful if you want to determine things such as the how long the element
228 * has been in the cache.
229 * <p>
230 * The last access time in the ElementAttributes should be current.
231 * <p>
232 * @param name Key the Serializable is stored as
233 * @return The ICacheElement<K, V> if the object is found or null
234 */
235 public ICacheElement<K, V> getCacheElement( K name )
236 {
237 return this.cacheControl.get( name );
238 }
239
240 /**
241 * Get multiple elements from the cache based on a set of cache keys.
242 * <p>
243 * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
244 * attributes.
245 * <p>
246 * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
247 * defensive copy is made.
248 * <p>
249 * This method is most useful if you want to determine things such as the how long the element
250 * has been in the cache.
251 * <p>
252 * The last access time in the ElementAttributes should be current.
253 * <p>
254 * @param names set of Serializable cache keys
255 * @return a map of K key to ICacheElement<K, V> element, or empty map if none of the keys are present
256 */
257 public Map<K, ICacheElement<K, V>> getCacheElements( Set<K> names )
258 {
259 return this.cacheControl.getMultiple( names );
260 }
261
262 /**
263 * Get multiple elements from the cache based on a set of cache keys.
264 * <p>
265 * This method returns the ICacheElement<K, V> wrapper which provides access to element info and other
266 * attributes.
267 * <p>
268 * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
269 * defensive copy is made.
270 * <p>
271 * This method is most useful if you want to determine things such as the how long the element
272 * has been in the cache.
273 * <p>
274 * The last access time in the ElementAttributes should be current.
275 * <p>
276 * @param pattern key search pattern
277 * @return a map of K key to ICacheElement<K, V> element, or empty map if no keys match the pattern
278 */
279 public Map<K, ICacheElement<K, V>> getMatchingCacheElements( String pattern )
280 {
281 return this.cacheControl.getMatching( pattern );
282 }
283
284 /**
285 * Place a new object in the cache, associated with key name. If there is currently an object
286 * associated with name in the region an ObjectExistsException is thrown. Names are scoped to a
287 * region so they must be unique within the region they are placed.
288 * <p>
289 * @param key Key object will be stored with
290 * @param value Object to store
291 * @exception CacheException and ObjectExistsException is thrown if the item is already in the
292 * cache.
293 */
294 public void putSafe( K key, V value )
295 throws CacheException
296 {
297 if ( this.cacheControl.get( key ) != null )
298 {
299 throw new ObjectExistsException( "putSafe failed. Object exists in the cache for key [" + key
300 + "]. Remove first or use a non-safe put to override the value." );
301 }
302 put( key, value );
303 }
304
305 /**
306 * Place a new object in the cache, associated with key name. If there is currently an object
307 * associated with name in the region it is replaced. Names are scoped to a region so they must
308 * be unique within the region they are placed. ObjectExistsException
309 * @param name Key object will be stored with
310 * @param obj Object to store
311 * @exception CacheException
312 */
313 public void put( K name, V obj )
314 throws CacheException
315 {
316 // Call put with a copy of the contained caches default attributes.
317 // the attributes are copied by the cacheControl
318 put( name, obj, this.cacheControl.getElementAttributes() );
319 }
320
321 /**
322 * Constructs a cache element with these attributes, and puts it into the cache.
323 * <p>
324 * If the key or the value is null, and InvalidArgumentException is thrown.
325 * <p>
326 * @see org.apache.jcs.access.behavior.ICacheAccess#put(java.lang.Object, java.lang.Object,
327 * org.apache.jcs.engine.behavior.IElementAttributes)
328 */
329 public void put( K key, V val, IElementAttributes attr )
330 throws CacheException
331 {
332 if ( key == null )
333 {
334 throw new InvalidArgumentException( "Key must not be null" );
335 }
336
337 if ( val == null )
338 {
339 throw new InvalidArgumentException( "Value must not be null" );
340 }
341
342 // Create the element and update. This may throw an IOException which
343 // should be wrapped by cache access.
344 try
345 {
346 CacheElement<K, V> ce = new CacheElement<K, V>( this.cacheControl.getCacheName(), key,
347 val );
348
349 ce.setElementAttributes( attr );
350
351 this.cacheControl.update( ce );
352 }
353 catch ( Exception e )
354 {
355 throw new CacheException( e );
356 }
357 }
358
359 /**
360 * Destroy the region and all objects within it. After calling this method, the Cache object can
361 * no longer be used as it will be closed.
362 * <p>
363 * @exception CacheException
364 * @deprecated
365 */
366 @Deprecated
367 public void destroy()
368 throws CacheException
369 {
370 try
371 {
372 this.cacheControl.removeAll();
373 }
374 catch ( IOException e )
375 {
376 throw new CacheException( e );
377 }
378 }
379
380 /**
381 * Removes all of the elements from a region.
382 * <p>
383 * @deprecated use clear()
384 * @throws CacheException
385 */
386 @Deprecated
387 public void remove()
388 throws CacheException
389 {
390 clear();
391 }
392
393 /**
394 * Removes all of the elements from a region.
395 * <p>
396 * @throws CacheException
397 */
398 public void clear()
399 throws CacheException
400 {
401 try
402 {
403 this.cacheControl.removeAll();
404 }
405 catch ( IOException e )
406 {
407 throw new CacheException( e );
408 }
409 }
410
411 /**
412 * Invalidate all objects associated with key name, removing all references to the objects from
413 * the cache.
414 * <p>
415 * @param name Key that specifies object to invalidate
416 * @exception CacheException
417 * @deprecated use remove
418 */
419 @Deprecated
420 public void destroy( K name )
421 throws CacheException
422 {
423 this.cacheControl.remove( name );
424 }
425
426 /**
427 * Removes a single item by name.
428 * <p>
429 * @param name the name of the item to remove.
430 * @throws CacheException
431 */
432 public void remove( K name )
433 throws CacheException
434 {
435 this.cacheControl.remove( name );
436 }
437
438 /**
439 * ResetAttributes allows for some of the attributes of a region to be reset in particular
440 * expiration time attributes, time to live, default time to live and idle time, and event
441 * handlers. Changing default settings on groups and regions will not affect existing objects.
442 * Only object loaded after the reset will use the new defaults. If no name argument is
443 * provided, the reset is applied to the region.
444 * <p>
445 * NOTE: this method is does not reset the attributes for items already in the cache. It could
446 * potentially do this for items in memory, and maybe on disk (which would be slow) but not
447 * remote items. Rather than have unpredictable behavior, this method just sets the default
448 * attributes.
449 * <p>
450 * TODO is should be renamed "setDefaultElementAttributes"
451 * <p>
452 * @deprecated As of release 1.3
453 * @see #setDefaultElementAttributes(IElementAttributes)
454 * @param attr New attributes for this region.
455 * @exception CacheException
456 * @exception InvalidHandleException
457 */
458 @Deprecated
459 public void resetElementAttributes( IElementAttributes attr )
460 throws CacheException, InvalidHandleException
461 {
462 this.cacheControl.setElementAttributes( attr );
463 }
464
465 /**
466 * This method is does not reset the attributes for items already in the cache. It could
467 * potentially do this for items in memory, and maybe on disk (which would be slow) but not
468 * remote items. Rather than have unpredictable behavior, this method just sets the default
469 * attributes. Items subsequently put into the cache will use these defaults if they do not
470 * specify specific attributes.
471 * <p>
472 * @param attr the default attributes.
473 * @throws CacheException if something goes wrong.
474 */
475 public void setDefaultElementAttributes( IElementAttributes attr )
476 throws CacheException
477 {
478 this.cacheControl.setElementAttributes( attr );
479 }
480
481 /**
482 * Reset attributes for a particular element in the cache. NOTE: this method is currently not
483 * implemented.
484 * <p>
485 * @param name Key of object to reset attributes for
486 * @param attr New attributes for the object
487 * @exception CacheException
488 * @exception InvalidHandleException if the item does not exist.
489 */
490 public void resetElementAttributes( K name, IElementAttributes attr )
491 throws CacheException, InvalidHandleException
492 {
493 ICacheElement<K, V> element = this.cacheControl.get( name );
494
495 if ( element == null )
496 {
497 throw new InvalidHandleException( "Object for name [" + name + "] is not in the cache" );
498 }
499
500 // Although it will work currently, don't assume pass by reference here,
501 // i.e. don't do this:
502 // element.setElementAttributes( attr );
503 // Another reason to call put is to force the changes to be distributed.
504
505 put( element.getKey(), element.getVal(), attr );
506 }
507
508 /**
509 * GetElementAttributes will return an attribute object describing the current attributes
510 * associated with the object name.
511 * <p>
512 * This was confusing, so I created a new method with a clear name.
513 * <p>
514 * @deprecated As of release 1.3
515 * @see #getDefaultElementAttributes
516 * @return Attributes for this region
517 * @exception CacheException
518 */
519 @Deprecated
520 public IElementAttributes getElementAttributes()
521 throws CacheException
522 {
523 return this.cacheControl.getElementAttributes();
524 }
525
526 /**
527 * Retrieves A COPY OF the default element attributes used by this region. This does not provide
528 * a reference to the element attributes.
529 * <p>
530 * Each time an element is added to the cache without element attributes, the default element
531 * attributes are cloned.
532 * <p>
533 * @return the deafualt element attributes used by this region.
534 * @throws CacheException
535 */
536 public IElementAttributes getDefaultElementAttributes()
537 throws CacheException
538 {
539 return this.cacheControl.getElementAttributes();
540 }
541
542 /**
543 * GetElementAttributes will return an attribute object describing the current attributes
544 * associated with the object name. The name object must override the Object.equals and
545 * Object.hashCode methods.
546 * <p>
547 * @param name Key of object to get attributes for
548 * @return Attributes for the object, null if object not in cache
549 * @exception CacheException
550 */
551 public IElementAttributes getElementAttributes( K name )
552 throws CacheException
553 {
554 IElementAttributes attr = null;
555
556 try
557 {
558 attr = this.cacheControl.getElementAttributes( name );
559 }
560 catch ( IOException ioe )
561 {
562 log.error( "Failure getting element attributes", ioe );
563 }
564
565 return attr;
566 }
567
568 /**
569 * This returns the ICacheStats object with information on this region and its auxiliaries.
570 * <p>
571 * This data can be formatted as needed.
572 * <p>
573 * @return ICacheStats
574 */
575 public ICacheStats getStatistics()
576 {
577 return this.cacheControl.getStatistics();
578 }
579
580 /**
581 * @return A String version of the stats.
582 */
583 public String getStats()
584 {
585 return this.cacheControl.getStats();
586 }
587
588 /**
589 * Dispose this region. Flushes objects to and closes auxiliary caches. This is a shutdown
590 * command!
591 * <p>
592 * To simply remove all elements from the region use clear().
593 */
594 public void dispose()
595 {
596 this.cacheControl.dispose();
597 }
598
599 /**
600 * Gets the ICompositeCacheAttributes of the cache region.
601 * <p>
602 * @return ICompositeCacheAttributes, the controllers config info, defined in the top section of
603 * a region definition.
604 */
605 public ICompositeCacheAttributes getCacheAttributes()
606 {
607 return this.cacheControl.getCacheAttributes();
608 }
609
610 /**
611 * Sets the ICompositeCacheAttributes of the cache region.
612 * <p>
613 * @param cattr The new ICompositeCacheAttribute value
614 */
615 public void setCacheAttributes( ICompositeCacheAttributes cattr )
616 {
617 this.cacheControl.setCacheAttributes( cattr );
618 }
619
620 /**
621 * This instructs the memory cache to remove the <i>numberToFree</i> according to its eviction
622 * policy. For example, the LRUMemoryCache will remove the <i>numberToFree</i> least recently
623 * used items. These will be spooled to disk if a disk auxiliary is available.
624 * <p>
625 * @param numberToFree
626 * @return the number that were removed. if you ask to free 5, but there are only 3, you will
627 * get 3.
628 * @throws CacheException
629 */
630 public int freeMemoryElements( int numberToFree )
631 throws CacheException
632 {
633 int numFreed = -1;
634 try
635 {
636 numFreed = this.cacheControl.getMemoryCache().freeElements( numberToFree );
637 }
638 catch ( IOException ioe )
639 {
640 String message = "Failure freeing memory elements. ";
641 log.error( message, ioe );
642 throw new CacheException( message + ioe.getMessage() );
643 }
644 return numFreed;
645 }
646 }