View Javadoc

1   package org.apache.jcs.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.io.Serializable;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.jcs.access.behavior.ICacheAccess;
28  import org.apache.jcs.access.exception.CacheException;
29  import org.apache.jcs.access.exception.InvalidArgumentException;
30  import org.apache.jcs.access.exception.InvalidHandleException;
31  import org.apache.jcs.access.exception.ObjectExistsException;
32  import org.apache.jcs.engine.CacheElement;
33  import org.apache.jcs.engine.behavior.ICacheElement;
34  import org.apache.jcs.engine.behavior.ICompositeCacheAttributes;
35  import org.apache.jcs.engine.behavior.IElementAttributes;
36  import org.apache.jcs.engine.control.CompositeCache;
37  import org.apache.jcs.engine.control.CompositeCacheManager;
38  import org.apache.jcs.engine.stats.behavior.ICacheStats;
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 items wrapper, the element configuration, put an
47   * item in the cache, remove an item, and clear a region.
48   * <p>
49   * The JCS class is the prefered way to access these methods.
50   */
51  public class CacheAccess
52      implements ICacheAccess
53  {
54      /*** The logger. */
55      private static final Log log = LogFactory.getLog( CacheAccess.class );
56  
57      /***
58       * Cache manager use by the various forms of defineRegion and getAccess
59       */
60      private static CompositeCacheManager cacheMgr;
61  
62      /***
63       * The cache that a given instance of this class provides access to.
64       * <p>
65       * @TODO Should this be the inteface?
66       */
67      protected CompositeCache cacheControl;
68  
69      /***
70       * Constructor for the CacheAccess object.
71       * <p>
72       * @param cacheControl The cache which the created instance accesses
73       */
74      public CacheAccess( CompositeCache cacheControl )
75      {
76          this.cacheControl = cacheControl;
77      }
78  
79      // ----------------------------- static methods for access to cache regions
80  
81      /***
82       * Define a new cache region with the given name. In the oracle specification, these attributes
83       * are global and not region specific, regional overirdes is a value add each region should be
84       * able to house both cache and element attribute sets. It is more efficient to define a cache
85       * in the props file and then strictly use the get access method. Use of the define region
86       * outside of an initialization block should be avoided.
87       * <p>
88       * @param name Name that will identify the region
89       * @return CacheAccess instance for the new region
90       * @exception CacheException
91       */
92      public static CacheAccess defineRegion( String name )
93          throws CacheException
94      {
95          ensureCacheManager();
96  
97          return new CacheAccess( cacheMgr.getCache( name ) );
98      }
99  
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 CacheAccess defineRegion( String name, ICompositeCacheAttributes cattr )
109         throws CacheException
110     {
111         ensureCacheManager();
112 
113         return new CacheAccess( cacheMgr.getCache( name, cattr ) );
114     }
115 
116     /***
117      * Define a new cache region with the specified name and attributes and return a CacheAccess to
118      * it.
119      * <p>
120      * @param name Name that will identify the region
121      * @param cattr CompositeCacheAttributes for the region
122      * @param attr Attributes for the region
123      * @return CacheAccess instance for the new region
124      * @exception CacheException
125      */
126     public static CacheAccess defineRegion( String name, ICompositeCacheAttributes cattr, IElementAttributes attr )
127         throws CacheException
128     {
129         ensureCacheManager();
130 
131         return new CacheAccess( cacheMgr.getCache( name, cattr, attr ) );
132     }
133 
134     /***
135      * Get a CacheAccess instance for the given region.
136      * <p>
137      * @param region Name that identifies the region
138      * @return CacheAccess instance for region
139      * @exception CacheException
140      */
141     public static CacheAccess getAccess( String region )
142         throws CacheException
143     {
144         ensureCacheManager();
145 
146         return new CacheAccess( cacheMgr.getCache( region ) );
147     }
148 
149     /***
150      * Get a CacheAccess instance for the given region with the given attributes.
151      * <p>
152      * @param region Name that identifies the region
153      * @param icca
154      * @return CacheAccess instance for region
155      * @exception CacheException
156      */
157     public static CacheAccess getAccess( String region, ICompositeCacheAttributes icca )
158         throws CacheException
159     {
160         ensureCacheManager();
161 
162         return new CacheAccess( cacheMgr.getCache( region, icca ) );
163     }
164 
165     /***
166      * Helper method which checks to make sure the cacheMgr class field is set, and if not requests
167      * an instance from CacheManagerFactory.
168      */
169     protected static void ensureCacheManager()
170     {
171         synchronized ( CacheAccess.class )
172         {
173             if ( cacheMgr == null )
174             {
175                 cacheMgr = CompositeCacheManager.getInstance();
176             }
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 Object get( Object name )
189     {
190         ICacheElement element = this.cacheControl.get( (Serializable) name );
191 
192         return ( element != null ) ? element.getVal() : null;
193     }
194 
195     /***
196      * This method returns the ICacheElement wrapper which provides access to element info and other
197      * attributes.
198      * <p>
199      * This returns a reference to the wrapper. Any modifications will be reflected in the cache. No
200      * defensive copy is made.
201      * <p>
202      * This method is most useful if you want to determine things such as the how long the element
203      * has been in the cache.
204      * <p>
205      * The last access time in teh ElementAttributes should be current.
206      * <p>
207      * @param name Key the object is stored as
208      * @return The ICacheElement if the object is found or null
209      */
210     public ICacheElement getCacheElement( Object name )
211     {
212         return this.cacheControl.get( (Serializable) name );
213     }
214 
215     /***
216      * Place a new object in the cache, associated with key name. If there is currently an object
217      * associated with name in the region an ObjectExistsException is thrown. Names are scoped to a
218      * region so they must be unique within the region they are placed.
219      * <p>
220      * @param key Key object will be stored with
221      * @param value Object to store
222      * @exception CacheException and ObjectExistsException is thrown if the item is already in the
223      *                cache.
224      */
225     public void putSafe( Object key, Object value )
226         throws CacheException
227     {
228         if ( this.cacheControl.get( (Serializable) key ) != null )
229         {
230             throw new ObjectExistsException( "putSafe failed.  Object exists in the cache for key [" + key
231                 + "].  Remove first or use a non-safe put to override the value." );
232         }
233         put( key, value );
234     }
235 
236     /***
237      * Place a new object in the cache, associated with key name. If there is currently an object
238      * associated with name in the region it is replaced. Names are scoped to a region so they must
239      * be unique within the region they are placed. ObjectExistsException
240      * @param name Key object will be stored with
241      * @param obj Object to store
242      * @exception CacheException
243      */
244     public void put( Object name, Object obj )
245         throws CacheException
246     {
247         // Call put with a copy of the contained caches default attributes.
248         // the attributes are copied by the cacheControl
249         put( name, obj, this.cacheControl.getElementAttributes() );
250     }
251 
252     /***
253      * Constructs a cache element with these attribures, and puts it into the cache.
254      * <p>
255      * If the key or the value is null, and InvalidArgumentException is thrown.
256      * <p>
257      * @see org.apache.jcs.access.behavior.ICacheAccess#put(java.lang.Object, java.lang.Object,
258      *      org.apache.jcs.engine.behavior.IElementAttributes)
259      */
260     public void put( Object key, Object val, IElementAttributes attr )
261         throws CacheException
262     {
263         if ( key == null )
264         {
265             throw new InvalidArgumentException( "Key must not be null" );
266         }
267         else if ( val == null )
268         {
269             throw new InvalidArgumentException( "Value must not be null" );
270         }
271 
272         // Create the element and update. This may throw an IOException which
273         // should be wrapped by cache access.
274         try
275         {
276             CacheElement ce = new CacheElement( this.cacheControl.getCacheName(), (Serializable) key,
277                                                 (Serializable) val );
278 
279             ce.setElementAttributes( attr );
280 
281             this.cacheControl.update( ce );
282         }
283         catch ( Exception e )
284         {
285             throw new CacheException( e );
286         }
287     }
288 
289     /***
290      * Destory the region and all objects within it. After calling this method, the Cache object can
291      * no longer be used as it will be closed.
292      * <p>
293      * @exception CacheException
294      * @deprecated
295      */
296     public void destroy()
297         throws CacheException
298     {
299         try
300         {
301             this.cacheControl.removeAll();
302         }
303         catch ( IOException e )
304         {
305             throw new CacheException( e );
306         }
307     }
308 
309     /***
310      * Removes all of the elements from a region.
311      * <p>
312      * @deprecated use clear()
313      * @throws CacheException
314      */
315     public void remove()
316         throws CacheException
317     {
318         clear();
319     }
320 
321     /***
322      * Removes all of the elements from a region.
323      * <p>
324      * @throws CacheException
325      */
326     public void clear()
327         throws CacheException
328     {
329         try
330         {
331             this.cacheControl.removeAll();
332         }
333         catch ( IOException e )
334         {
335             throw new CacheException( e );
336         }
337     }
338 
339     /***
340      * Invalidate all objects associated with key name, removing all references to the objects from
341      * the cache.
342      * <p>
343      * @param name Key that specifies object to invalidate
344      * @exception CacheException
345      * @deprecated use remove
346      */
347     public void destroy( Object name )
348         throws CacheException
349     {
350         this.cacheControl.remove( (Serializable) name );
351     }
352 
353     /***
354      * Removes a single item by name.
355      * <p>
356      * @param name the name of the item to remove.
357      * @throws CacheException
358      */
359     public void remove( Object name )
360         throws CacheException
361     {
362         this.cacheControl.remove( (Serializable) name );
363     }
364 
365     /***
366      * ResetAttributes allows for some of the attributes of a region to be reset in particular
367      * expiration time attriubtes, time to live, default time to live and idle time, and event
368      * handlers. Changing default settings on groups and regions will not affect existing objects.
369      * Only object loaded after the reset will use the new defaults. If no name argument is
370      * provided, the reset is applied to the region.
371      * <p>
372      * NOTE: this method is does not reset the attributes for items already in the cache. It could
373      * potentially do this for items in memory, and maybe on disk (which would be slow) but not
374      * remote items. Rather than have unpredicatble behavior, this method just sets the default
375      * attributes.
376      * <p>
377      * TODO is should be renamed "setDefaultElementAttributes"
378      * <p>
379      * @deprecated As of release 1.3
380      * @see setDefaultElementAttributes
381      * @param attr New attributes for this region.
382      * @exception CacheException
383      * @exception InvalidHandleException
384      */
385     public void resetElementAttributes( IElementAttributes attr )
386         throws CacheException, InvalidHandleException
387     {
388         this.cacheControl.setElementAttributes( attr );
389     }
390 
391     /***
392      * This method is does not reset the attributes for items already in the cache. It could
393      * potentially do this for items in memory, and maybe on disk (which would be slow) but not
394      * remote items. Rather than have unpredicatble behavior, this method just sets the default
395      * attributes. Items subsequently put into the cache will use these defaults if they do not
396      * specify specific attributes.
397      * <p>
398      * @param attr the default attributes.
399      * @throws CacheException if something goes wrong.
400      */
401     public void setDefaultElementAttributes( IElementAttributes attr )
402         throws CacheException
403     {
404         this.cacheControl.setElementAttributes( attr );
405     }
406 
407     /***
408      * Reset attributes for a particular element in the cache. NOTE: this method is currently not
409      * implemented.
410      * <p>
411      * @param name Key of object to reset attributes for
412      * @param attr New attributes for the object
413      * @exception CacheException
414      * @exception InvalidHandleException if the item does not exist.
415      */
416     public void resetElementAttributes( Object name, IElementAttributes attr )
417         throws CacheException, InvalidHandleException
418     {
419         ICacheElement element = this.cacheControl.get( (Serializable) name );
420         if ( element == null )
421         {
422             throw new InvalidHandleException( "Object for name [" + name + "] is not in the cache" );
423         }
424 
425         // Although it will work currently, don't assume pass by reference here,
426         // i.e. don't do this:
427         // element.setElementAttributes( attr );
428         // Another reason to call put is to force the changes to be distributed.
429         put( element.getKey(), element.getVal(), attr );
430 
431     }
432 
433     /***
434      * GetElementAttributes will return an attribute object describing the current attributes
435      * associated with the object name.
436      * <p>
437      * This was confusing, so I created a new method with a clear name.
438      * <p>
439      * @deprecated As of release 1.3
440      * @see getDefaultElementAttributes
441      * @return Attributes for this region
442      * @exception CacheException
443      */
444     public IElementAttributes getElementAttributes()
445         throws CacheException
446     {
447         return this.cacheControl.getElementAttributes();
448     }
449 
450     /***
451      * Retrieves A COPY OF the default element attributes used by this region. This does not provide
452      * a reference to the element attributes.
453      * <p>
454      * Each time an element is added to the cache without element attributes, the default element
455      * attributes are cloned.
456      * <p>
457      * @return the deafualt element attributes used by this region.
458      * @throws CacheException
459      */
460     public IElementAttributes getDefaultElementAttributes()
461         throws CacheException
462     {
463         return this.cacheControl.getElementAttributes();
464     }
465 
466     /***
467      * GetElementAttributes will return an attribute object describing the current attributes
468      * associated with the object name. The name object must override the Object.equals and
469      * Object.hashCode methods.
470      * <p>
471      * @param name Key of object to get attributes for
472      * @return Attributes for the object, null if object not in cache
473      * @exception CacheException
474      */
475     public IElementAttributes getElementAttributes( Object name )
476         throws CacheException
477     {
478         IElementAttributes attr = null;
479 
480         try
481         {
482             attr = this.cacheControl.getElementAttributes( (Serializable) name );
483         }
484         catch ( IOException ioe )
485         {
486             log.error( "Failure getting element attributes", ioe );
487         }
488 
489         return attr;
490     }
491 
492     /***
493      * This returns the ICacheStats object with information on this region and its auxiliaries.
494      * <p>
495      * This data can be formatted as needed.
496      * <p>
497      * @return ICacheStats
498      */
499     public ICacheStats getStatistics()
500     {
501         return this.cacheControl.getStatistics();
502     }
503 
504     /***
505      * @return A String version of the stats.
506      */
507     public String getStats()
508     {
509         return this.cacheControl.getStats();
510     }
511 
512     /***
513      * Dispose this region. Flushes objects to and closes auxiliary caches. This is a shutdown
514      * command!
515      * <p>
516      * To simply remove all elements from the region use clear().
517      */
518     public void dispose()
519     {
520         this.cacheControl.dispose();
521     }
522 
523     /***
524      * Gets the ICompositeCacheAttributes of the cache region.
525      * <p>
526      * @return ICompositeCacheAttributes, the controllers config info, defined in the top section of
527      *         a region definition.
528      */
529     public ICompositeCacheAttributes getCacheAttributes()
530     {
531         return this.cacheControl.getCacheAttributes();
532     }
533 
534     /***
535      * Sets the ICompositeCacheAttributes of the cache region.
536      * <p>
537      * @param cattr The new ICompositeCacheAttribute value
538      */
539     public void setCacheAttributes( ICompositeCacheAttributes cattr )
540     {
541         this.cacheControl.setCacheAttributes( cattr );
542     }
543 
544     /***
545      * This instructs the memory cache to remove the <i>numberToFree</i> according to its eviction
546      * policy. For example, the LRUMemoryCache will remove the <i>numberToFree</i> least recently
547      * used items. These will be spooled to disk if a disk auxiliary is available.
548      * <p>
549      * @param numberToFree
550      * @return the number that were removed. if you ask to free 5, but there are only 3, you will
551      *         get 3.
552      * @throws CacheException
553      */
554     public int freeMemoryElements( int numberToFree )
555         throws CacheException
556     {
557         int numFreed = -1;
558         try
559         {
560             numFreed = this.cacheControl.getMemoryCache().freeElements( numberToFree );
561         }
562         catch ( IOException ioe )
563         {
564             String message = "Failure freeing memory elements.  ";
565             log.error( message, ioe );
566             throw new CacheException( message + ioe.getMessage() );
567         }
568         return numFreed;
569     }
570 }