KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > appserv > util > cache > BaseCache


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /**
25  * Copyright 2000-2001 by iPlanet/Sun Microsystems, Inc.,
26  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
27  * All rights reserved.
28  */

29  
30 package com.sun.appserv.util.cache;
31
32 import java.text.MessageFormat JavaDoc;
33
34 import java.util.ArrayList JavaDoc;
35 import java.util.Enumeration JavaDoc;
36 import java.util.Vector JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.HashMap JavaDoc;
39 import java.util.Properties JavaDoc;
40 import java.util.Iterator JavaDoc;
41 import java.util.ResourceBundle JavaDoc;
42
43 import com.sun.common.util.logging.LogDomains;
44
45 /**
46  * BaseCache
47  * Generic in-memory, abstract cache
48  */

49 public class BaseCache implements Cache {
50     
51     /**
52      * The resource bundle containing the localized message strings.
53      */

54     protected static ResourceBundle JavaDoc _rb = null;
55
56     static final int MAX_ENTRIES = 1 << 30;
57     static final float DEFAULT_LOAD_FACTOR = 0.75f;
58
59     // maximum number of entries this cache may ever hold
60
int maxEntries;
61
62     // the number of cache entries in this cache
63
protected int entryCount;
64     private Object JavaDoc entryCountLk = new Object JavaDoc();
65
66     /** threshold for the cache; once the threshold is reached
67      * entries are removed to accomodate newer inserts
68      */

69     protected int threshold = 0;
70
71     // the number of cache hits
72
private int hitCount;
73     private Object JavaDoc hitCountLk = new Object JavaDoc();
74
75     // the number of cache misses
76
private int missCount;
77     private Object JavaDoc missCountLk = new Object JavaDoc();
78
79     // the number of cache item removals
80
private int removalCount;
81     private Object JavaDoc removalCountLk = new Object JavaDoc();
82
83     // the number of cache item refreshes
84
private int refreshCount;
85     private Object JavaDoc refreshCountLk = new Object JavaDoc();
86
87     // the number of times an item was added to cache
88
private int addCount;
89     private Object JavaDoc addCountLk = new Object JavaDoc();
90
91     // the number of times the cache overflowed
92
private int overflowCount;
93     private Object JavaDoc overflowCountLk = new Object JavaDoc();
94
95     // table size
96
protected int maxBuckets;
97
98     // cache entries hash table
99
protected CacheItem[] buckets;
100     // bucket-wide locks
101
protected Object JavaDoc[] bucketLocks;
102
103     // boolean status and locks for item thread-safe refreshes
104
protected boolean[] refreshFlags;
105
106     protected ArrayList JavaDoc listeners = new ArrayList JavaDoc();
107
108     /**
109      * default constructor for the basic cache
110      */

111     public BaseCache() { }
112
113     /**
114      * initialize the cache
115      * @param maxEntries maximum number of entries expected in the cache
116      * @param props opaque list of properties for a given cache implementation
117      * @throws a generic Exception if the initialization failed
118      */

119     public void init(int maxEntries, Properties JavaDoc props) throws Exception JavaDoc {
120         init(maxEntries, DEFAULT_LOAD_FACTOR, props);
121     }
122
123     /**
124      * initialize the cache
125      * @param maxEntries maximum number of entries expected in the cache
126      * @param loadFactor the load factor
127      * @param props opaque list of properties for a given cache implementation
128      * @throws a generic Exception if the initialization failed
129      */

130     public void init(int maxEntries, float loadFactor, Properties JavaDoc props) {
131
132         // web container logger
133
_rb = LogDomains.getLogger(LogDomains.CMN_LOGGER).getResourceBundle();
134
135         if (maxEntries <= 0) {
136             String JavaDoc msg = _rb.getString("cache.BaseCache.illegalMaxEntries");
137
138             Integer JavaDoc obj = new Integer JavaDoc(maxEntries);
139             Object JavaDoc[] params = { obj };
140             msg = MessageFormat.format(msg, params);
141
142             throw new IllegalArgumentException JavaDoc(msg);
143         }
144
145         if (maxEntries > MAX_ENTRIES)
146              maxEntries = MAX_ENTRIES;
147
148         this.maxEntries = maxEntries;
149
150         // find a power of 2 >= maxEntries
151
maxBuckets = 1;
152         while (maxBuckets < maxEntries)
153             maxBuckets <<= 1;
154
155         //Cannot have the loadfactor as a negative value
156
if( loadFactor < 0 )
157             loadFactor = 0;
158
159         /** initialize the threshold; a zero value for maxEntries
160          * implies no caching.
161          */

162         if (maxEntries != 0) {
163             threshold = (int)(maxEntries * loadFactor) + 1;
164         }
165
166         // create the cache and the bucket locks
167
entryCount = 0;
168         buckets = new CacheItem[maxBuckets];
169         bucketLocks = new Object JavaDoc[maxBuckets];
170         refreshFlags = new boolean[maxBuckets];
171
172         for (int i=0; i<maxBuckets; i++) {
173             buckets[i] = null;
174             bucketLocks[i] = new Object JavaDoc();
175             refreshFlags[i] = false;
176         }
177     }
178
179     /**
180      * add the cache module listener
181      * @param listener <code>CacheListener</code> implementation
182      */

183     public void addCacheListener(CacheListener listener) {
184         listeners.add(listener);
185     }
186
187     /**
188      * Returns a hash code for non-null Object x.
189      * @See also <code>HashMap</code>
190      */

191     protected int hash(Object JavaDoc x) {
192         int h = x.hashCode();
193         return h - (h << 7); // i.e., -127 * h
194
}
195
196     /**
197      * Check for equality of non-null reference x and possibly-null y.
198      */

199     protected boolean eq(Object JavaDoc x, Object JavaDoc y) {
200         return x == y || x.equals(y);
201     }
202
203     /**
204      * increase the threshold
205      */

206     protected void handleOverflow() {
207         // just double the threshold; this may degenerate the cache.
208
threshold = (threshold * 2);
209         incrementOverflowCount();
210     }
211
212     /**
213      * this item is just added to the cache
214      * @param item <code>CacheItem</code> that was created
215      * @return a overflow item; may be null
216      * Cache bucket is already synchronized by the caller
217      *
218      * Here, if cache is overflowing (i.e. reached threshold); this class
219      * simply makes the cache unbounded by raising the threshold. Subclasses
220      * are expected to provide a robust cache replacement algorithm.
221      *
222      * Subclasses should enhance this implemntation.
223      */

224     protected CacheItem itemAdded(CacheItem item) {
225         if (isThresholdReached()) {
226             handleOverflow();
227         }
228         return null;
229     }
230
231     /**
232      * this item is accessed
233      * @param item <code>CacheItem</code> accessed
234      *
235      * Cache bucket is already synchronized by the caller
236      */

237     protected void itemAccessed(CacheItem item) { }
238
239     /**
240      * item value has been refreshed
241      * @param item <code>CacheItem</code> that was refreshed
242      * @param oldSize size of the previous value that was refreshed
243      * Cache bucket is already synchronized by the caller
244      */

245     protected void itemRefreshed(CacheItem item, int oldSize) { }
246
247     /**
248      * item value has been removed from the cache
249      * @param item <code>CacheItem</code> that was just removed
250      *
251      * Cache bucket is already synchronized by the caller
252      */

253     protected void itemRemoved(CacheItem item) { }
254
255     /**
256      * Cannot find an item with the given key and hashCode
257      * @param key <code>Object</code> that is not found
258      * @param hashCode <code>int</code> its hashCode
259      *
260      * @returns the Object value associated with the item
261      * Cache bucket is already synchronized by the caller
262      */

263     protected Object JavaDoc loadValue(Object JavaDoc key, int hashCode) {
264         return null;
265     }
266
267     /**
268      * create new item
269      * @param hashCode for the entry
270      * @param key <code>Object</code> key
271      * @param value <code>Object</code> value
272      * @param size size in bytes of the item
273      * subclasses may override to provide their own CacheItem extensions
274      * e.g. one that permits persistence.
275      */

276     protected CacheItem createItem(int hashCode, Object JavaDoc key,
277                                         Object JavaDoc value, int size) {
278         return new CacheItem(hashCode, key, value, size);
279     }
280  
281     /**
282      * has cache reached its threshold
283      * @return true when the cache reached its threshold
284      */

285     protected boolean isThresholdReached() {
286         return (entryCount > threshold);
287     }
288
289     /**
290      * get the index of the item in the cache
291      * @param hashCode of the entry
292      * @return the index to be used in the cache
293      */

294     protected final int getIndex(int hashCode) {
295         return (hashCode & (maxBuckets - 1));
296     }
297
298     /**
299      * get the index of the item given a key
300      * @param key of the entry
301      * @return the index to be used in the cache
302      */

303     public final int getIndex(Object JavaDoc key) {
304         return getIndex(hash(key));
305     }
306
307     /**
308      * get the item stored at the key.
309      * @param key lookup key
310      * @returns the item stored at the key; null if not found.
311      */

312     public Object JavaDoc get(Object JavaDoc key) {
313         int hashCode = hash(key);
314
315         return get(hashCode, key);
316     }
317
318     /**
319      * get the item stored at the given pre-computed hash code and the key.
320      * @param key lookup key
321      * @returns the item stored at the key; null if not found.
322      */

323     public Object JavaDoc get(int hashCode, Object JavaDoc key) {
324
325         int index = getIndex(hashCode);
326         Object JavaDoc value;
327         CacheItem item = null;
328
329         synchronized (bucketLocks[index]) {
330             item = buckets[index];
331
332             for (; item != null; item = item.next) {
333                 if ( (hashCode == item.hashCode) && eq(key, item.key) ) {
334                     break;
335                 }
336             }
337
338             // update the stats in line
339
if (item != null) {
340                 value = item.getValue();
341                 itemAccessed(item);
342             }
343             else
344                 value = loadValue(key, hashCode);
345         }
346
347         if (item != null)
348             incrementHitCount();
349         else
350             incrementMissCount();
351
352         return value;
353     }
354         
355     /**
356      * check if the cache contains the item at the key
357      * @param key lookup key
358      * @returns true if there is an item stored at the key; false if not.
359      */

360     public boolean contains(Object JavaDoc key) {
361         return (get(key) != null);
362     }
363     
364     /**
365      * get all the items stored at the key.
366      * @param key lookup key
367      * @returns an Iterator over the items with the given key.
368      */

369     public Iterator JavaDoc getAll(Object JavaDoc key) {
370         int hashCode = hash(key);
371         int index = getIndex(hashCode);
372
373         ArrayList JavaDoc valueList = new ArrayList JavaDoc(entryCount);
374         synchronized (bucketLocks[index]) {
375             CacheItem item = buckets[index];
376
377             for (; item != null; item = item.next) {
378                 if ( (hashCode == item.hashCode) && eq(key, item.key) ) {
379                     incrementHitCount();
380                     valueList.add(item.getValue());
381                 }
382             }
383
384         }
385
386         return valueList.iterator();
387     }
388
389     /**
390      * get an Iterator for the keys stored in the cache
391      * @returns an Iterator
392      */

393     public Iterator JavaDoc keys() {
394         ArrayList JavaDoc keyList = new ArrayList JavaDoc(entryCount);
395
396         for (int index=0; index < maxBuckets; index++) {
397             synchronized (bucketLocks[index]) {
398                 for (CacheItem item = buckets[index]; item != null;
399                                 item = item.next) {
400                     keyList.add(item.key);
401                 }
402             }
403         }
404
405         return keyList.iterator();
406     }
407
408     /**
409      * get an Enumeration for the keys stored in the cache
410      * @returns an Enumeration
411      * XXX: should use Iterator which is based on Collections
412      */

413     public Enumeration JavaDoc elements() {
414         Vector JavaDoc keyList = new Vector JavaDoc();
415
416         for (int index=0; index < maxBuckets; index++) {
417             synchronized (bucketLocks[index]) {
418                 for (CacheItem item = buckets[index]; item != null;
419                                 item = item.next) {
420                     keyList.addElement(item.key);
421                 }
422             }
423         }
424
425         return keyList.elements();
426     }
427
428     /**
429      * get an Iterator for the values stored in the cache
430      * @returns an Iterator
431      */

432     public Iterator JavaDoc values() {
433         ArrayList JavaDoc valueList = new ArrayList JavaDoc(entryCount);
434
435         for (int index=0; index < maxBuckets; index++) {
436             synchronized (bucketLocks[index]) {
437                 for (CacheItem item = buckets[index]; item != null;
438                                 item = item.next) {
439                     valueList.add(item.value);
440                 }
441             }
442         }
443
444         return valueList.iterator();
445     }
446
447     /**
448     /**
449      * cache the given value at the specified key and return previous value
450      * @param key lookup key
451      * @param object item value to be stored
452      * @returns the previous item stored at the key; null if not found.
453      */

454     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
455         int hashCode = hash(key);
456
457         return _put(hashCode, key, value, -1, false);
458     }
459
460     /**
461      * cache the given value at the specified key and return previous value
462      * @param key lookup key
463      * @param object item value to be stored
464      * @param size in bytes of the value being cached
465      * @returns the previous item stored at the key; null if not found.
466      */

467     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value, int size) {
468         int hashCode = hash(key);
469
470         return _put(hashCode, key, value, size, false);
471     }
472
473     /**
474      * add the given value to the cache at the specified key
475      * @param key lookup key
476      * @param object item value to be stored
477      */

478     public void add(Object JavaDoc key, Object JavaDoc value) {
479         int hashCode = hash(key);
480
481         _put(hashCode, key, value, -1, true);
482     }
483
484     /**
485      * add the given value with specified size to the cache at specified key
486      * @param key lookup key
487      * @param object item value to be stored
488      * @param size in bytes of the value being added
489      *
490      * This function is suitable for multi-valued keys.
491      */

492     public void add(Object JavaDoc key, Object JavaDoc value, int size) {
493         int hashCode = hash(key);
494
495         _put(hashCode, key, value, size, true);
496     }
497
498     /**
499      * cache the given value at the specified key and return previous value
500      * @param hashCode previously computed hashCode for the key
501      * @param key lookup key
502      * @param object item value to be stored
503      * @param size in bytes of the value being cached
504      * @param addValue treate this operation to add (default is to replace)
505      * @returns the previous item stored at the key; null if not found.
506      *
507      * Note: This can be used just to refresh the cached item as well, altho
508      * it may call trimCache() if the cache reached its threshold -- which is
509      * is probably not very intuitive.
510      */

511     protected Object JavaDoc _put(int hashCode, Object JavaDoc key,
512                             Object JavaDoc value, int size, boolean addValue) {
513         int index = getIndex(hashCode);
514
515         CacheItem item, newItem = null, oldItem = null, overflow = null;
516         Object JavaDoc oldValue;
517         int oldSize = 0;
518
519         // lookup the item
520
synchronized (bucketLocks[index]) {
521             for (item = buckets[index]; item != null; item = item.next) {
522                 if ((hashCode == item.hashCode) && eq(key, item.key)) {
523
524                     oldItem = item;
525                     break;
526                 }
527             }
528
529             // if there was no item in the cache, insert the given item
530
if (addValue || oldItem == null) {
531                 newItem = createItem(hashCode, key, value, size);
532         
533                 // add the item at the head of the bucket list
534
newItem.next = buckets[index];
535                 buckets[index] = newItem;
536
537                 oldValue = null;
538                 overflow = itemAdded(newItem);
539             }
540             else {
541                 oldSize = oldItem.getSize();
542                 oldValue = oldItem.refreshValue(value, size);
543                 itemRefreshed(oldItem, oldSize);
544             }
545         }
546
547         if (newItem != null) {
548             incrementEntryCount();
549             incrementAddCount();
550
551             // make sure we are are not crossing the threshold
552
if (overflow != null)
553                 trimItem(overflow);
554         }
555         else
556             incrementRefreshCount();
557
558         return oldValue;
559     }
560
561     /**
562      * remove the item stored at the key.
563      * @param key lookup key
564      * @returns the item stored at the key; null if not found.
565      */

566     public Object JavaDoc remove(Object JavaDoc key) {
567         int hashCode = hash(key);
568
569         Object JavaDoc retVal = null;
570         CacheItem removed = _remove( hashCode, key, null);
571         
572         if (removed != null)
573             retVal = removed.getValue();
574         return retVal;
575     }
576
577     /**
578      * remove the item stored at the key.
579      * @param hashCode a precomputed hashCode
580      * @param key lookup key
581      * @returns the item stored at the key; null if not found.
582      */

583     public Object JavaDoc remove(int hashCode, Object JavaDoc key) {
584         Object JavaDoc retVal = null;
585         CacheItem removed = _remove( hashCode, key, null);
586         
587         if (removed != null)
588             retVal = removed.getValue();
589         return retVal;
590     }
591
592     /**
593      * remove the given value stored at the key; value-specific removals.
594      * @param key lookup key
595      * @param value to match (for a multi-valued keys)
596      * @returns the item stored at the key; null if not found.
597      */

598     public Object JavaDoc remove(Object JavaDoc key, Object JavaDoc value) {
599         int hashCode = hash(key);
600
601         Object JavaDoc retVal = null;
602         CacheItem removed = _remove( hashCode, key, value);
603         
604         if (removed != null)
605             retVal = removed.getValue();
606         return retVal;
607     }
608
609     /**
610      * remove the item stored at the key.
611      * @param hashCode a precomputed hashCode
612      * @param key lookup key
613      * @param value of the item to be matched
614      * @returns the item stored at the key; null if not found.
615      */

616     protected CacheItem _remove(int hashCode, Object JavaDoc key, Object JavaDoc value) {
617         int index = getIndex(hashCode);
618
619         CacheItem prev = null, item = null;
620
621         synchronized (bucketLocks[index]) {
622             for (item = buckets[index]; item != null; item = item.next) {
623                 if (hashCode == item.hashCode && key.equals(item.key)) {
624
625                     if (value == null || value == item.value) {
626
627                         if (prev == null) {
628                             buckets[index] = item.next;
629                         } else {
630                             prev.next = item.next;
631                         }
632                         item.next = null;
633
634                         itemRemoved(item);
635                         break;
636                     }
637                 }
638                 prev = item;
639             }
640         }
641         
642         if (item != null) {
643             decrementEntryCount();
644             incrementRemovalCount();
645
646             incrementHitCount();
647         } else
648             incrementMissCount();
649
650         return item;
651     }
652
653     /**
654      * remove the item stored at the key.
655      * @param item CacheItem to be removed
656      * @return the item stored at the key; null if not found.
657      */

658     protected CacheItem _removeItem(CacheItem ritem) {
659
660         int index = getIndex(ritem.hashCode);
661
662         CacheItem prev = null, item = null;
663
664         synchronized (bucketLocks[index]) {
665             for (item = buckets[index]; item != null; item = item.next) {
666                 if (item == ritem) {
667                     if (prev == null) {
668                         buckets[index] = item.next;
669                     } else {
670                         prev.next = item.next;
671                     }
672                     item.next = null;
673                     break;
674                 }
675                 prev = item;
676             }
677         }
678         
679         if (item != null) {
680             decrementEntryCount();
681         }
682
683         return item;
684     }
685
686     /**
687      * remove all the item with the given key.
688      * @param key lookup key
689      */

690     public void removeAll(Object JavaDoc key) {
691         int hashCode = hash(key);
692         int index = getIndex(hashCode);
693
694         CacheItem prev = null, item = null;
695         ArrayList JavaDoc items = new ArrayList JavaDoc(entryCount);
696
697         synchronized (bucketLocks[index]) {
698             for (item = buckets[index]; item != null;
699                                     item = item.next) {
700                 if (hashCode == item.hashCode && key.equals(item.key)) {
701                         if (prev == null) {
702                             buckets[index] = item.next;
703                         } else {
704                             prev.next = item.next;
705                         }
706                         item.next = null;
707         
708                         decrementEntryCount();
709                         incrementRemovalCount();
710
711                         items.add(item);
712                 }
713                 prev = item;
714             }
715         }
716
717         // notify subclasses
718
for (int i = 0; i < items.size(); i++) {
719             itemRemoved((CacheItem)items.get(i));
720         }
721     }
722
723     /**
724      * trim the item from the cache and notify listeners
725      * @param item to be trimmed
726      */

727     protected void trimItem(CacheItem item) {
728         CacheItem removed = _removeItem(item);
729
730         if (removed != null) {
731             for (int i = 0; i < listeners.size(); i++) {
732                 CacheListener listener = (CacheListener) listeners.get(i);
733                 listener.trimEvent(removed.key, removed.value);
734             }
735         }
736     }
737
738     /**
739      * wait for a refresh on the object associated with the key
740      * @param key lookup key
741      * @returns true on successful notification, or false if there is
742      * no thread refreshing this entry.
743      */

744     public boolean waitRefresh(int index) {
745         synchronized (bucketLocks[index]) {
746             if (refreshFlags[index] == false) {
747                 refreshFlags[index] = true;
748                 return false;
749             }
750
751             // wait till refresh is finished
752
try {
753                 bucketLocks[index].wait();
754             } catch (InterruptedException JavaDoc ie) {}
755         }
756         return true;
757     }
758
759     /**
760      * notify threads waiting for a refresh on the object associated with the key
761      * @param key lookup key
762      */

763     public void notifyRefresh(int index) {
764         // notify other threads waiting for refresh
765
synchronized (bucketLocks[index]) {
766             refreshFlags[index] = false;
767             bucketLocks[index].notifyAll();
768         }
769     }
770
771     /**
772      * clear all the entries from the cache.
773      * @returns the number of entries cleared from the cache
774      */

775     public int clear() {
776         
777         CacheItem item=null, next=null;
778         int count = 0;
779
780         for (int index = 0; index < maxBuckets; index++) {
781             synchronized (bucketLocks[index]) {
782                 for (item = buckets[index]; item != null;
783                                             item = item.next) {
784                     next = item.next;
785                     item.next = null;
786
787                     count++;
788                     decrementEntryCount();
789                     itemRemoved(item);
790
791                     if (entryCount == 0)
792                         break;
793                 }
794                 buckets[index] = null;
795             }
796         }
797
798
799         return count;
800     }
801
802     /**
803      * trim the expired entries from the cache.
804      * @param maxCount maximum number of invalid entries to trim
805      * specify Integer.MAX_VALUE to trim all timedout entries
806      *
807      * This call is to be scheduled by a thread managed by the container.
808      */

809     public void trimExpiredEntries(int maxCount) {}
810
811     /**
812      * get the number of entries in the cache
813      * @return the number of entries the cache currently holds
814      */

815     public int getEntryCount() {
816         return entryCount;
817     }
818
819     /*** methods for monitoring the cache ***/
820
821     /**
822      * is this cache empty?
823      * @returns true if the cache is empty; false otherwise.
824      */

825     public boolean isEmpty() {
826         return (entryCount == 0);
827     }
828
829     /**
830      * synchronized counter updates
831      */

832     protected final void incrementEntryCount() {
833         synchronized(entryCountLk) {
834             entryCount++;
835         }
836     }
837
838     protected final void decrementEntryCount() {
839         synchronized(entryCountLk) {
840             entryCount--;
841         }
842     }
843
844     protected final void incrementHitCount() {
845         synchronized (hitCountLk) {
846             hitCount++;
847         }
848     }
849
850     protected final void incrementMissCount() {
851         synchronized (missCountLk) {
852             missCount++;
853         }
854     }
855
856     protected final void incrementRemovalCount() {
857         synchronized (removalCountLk) {
858             removalCount++;
859         }
860     }
861
862     protected final void incrementRefreshCount() {
863         synchronized (refreshCountLk) {
864             refreshCount++;
865         }
866     }
867
868     protected final void incrementAddCount() {
869         synchronized (addCountLk) {
870             addCount++;
871         }
872     }
873
874     protected final void incrementOverflowCount() {
875         synchronized (overflowCountLk) {
876             overflowCount++;
877         }
878     }
879
880     /**
881      * get generic stats from subclasses
882      */

883
884     /**
885      * get the desired statistic counter
886      * @param key to corresponding stat
887      * @return an Object corresponding to the stat
888      * See also: Constant.java for the key
889      */

890     public Object JavaDoc getStatByName(String JavaDoc key) {
891         Object JavaDoc stat = null;
892
893         if (key == null)
894             return null;
895
896         if (key.equals(Constants.STAT_BASECACHE_MAX_ENTRIES))
897             stat = new Integer JavaDoc(maxEntries);
898         else if (key.equals(Constants.STAT_BASECACHE_THRESHOLD))
899             stat = new Integer JavaDoc(threshold);
900         else if (key.equals(Constants.STAT_BASECACHE_TABLE_SIZE))
901             stat = new Integer JavaDoc(maxBuckets);
902         else if (key.equals(Constants.STAT_BASECACHE_ENTRY_COUNT))
903             stat = new Integer JavaDoc(entryCount);
904         else if (key.equals(Constants.STAT_BASECACHE_HIT_COUNT))
905             stat = new Integer JavaDoc(hitCount);
906         else if (key.equals(Constants.STAT_BASECACHE_MISS_COUNT))
907             stat = new Integer JavaDoc(missCount);
908         else if (key.equals(Constants.STAT_BASECACHE_REMOVAL_COUNT))
909             stat = new Integer JavaDoc(removalCount);
910         else if (key.equals(Constants.STAT_BASECACHE_REFRESH_COUNT))
911             stat = new Integer JavaDoc(refreshCount);
912         else if (key.equals(Constants.STAT_BASECACHE_OVERFLOW_COUNT))
913             stat = new Integer JavaDoc(overflowCount);
914         else if (key.equals(Constants.STAT_BASECACHE_ADD_COUNT))
915             stat = new Integer JavaDoc(addCount);
916
917         return stat;
918     }
919
920     /**
921      * get the stats snapshot
922      * @return a Map of stats
923      * See also: Constant.java for the keys
924      */

925     public Map JavaDoc getStats() {
926         HashMap JavaDoc stats = new HashMap JavaDoc();
927
928         stats.put(Constants.STAT_BASECACHE_MAX_ENTRIES, new Integer JavaDoc(maxEntries));
929         stats.put(Constants.STAT_BASECACHE_THRESHOLD, new Integer JavaDoc(threshold));
930         stats.put(Constants.STAT_BASECACHE_TABLE_SIZE, new Integer JavaDoc(maxBuckets));
931         stats.put(Constants.STAT_BASECACHE_ENTRY_COUNT, new Integer JavaDoc(entryCount));
932         stats.put(Constants.STAT_BASECACHE_HIT_COUNT, new Integer JavaDoc(hitCount));
933         stats.put(Constants.STAT_BASECACHE_MISS_COUNT, new Integer JavaDoc(missCount));
934         stats.put(Constants.STAT_BASECACHE_REMOVAL_COUNT, new Integer JavaDoc(removalCount));
935         stats.put(Constants.STAT_BASECACHE_REFRESH_COUNT, new Integer JavaDoc(refreshCount));
936         stats.put(Constants.STAT_BASECACHE_OVERFLOW_COUNT, new Integer JavaDoc(overflowCount));
937         stats.put(Constants.STAT_BASECACHE_ADD_COUNT, new Integer JavaDoc(addCount));
938
939         return stats;
940     }
941
942     /**
943      * Sets all references to null. This method should be called
944      * at the end of this object's life cycle.
945      */

946     public void destroy() {
947         if ((listeners != null) && (buckets != null) && (bucketLocks != null)) {
948             clear();
949             listeners.clear();
950         }
951
952         entryCountLk = null;
953         hitCountLk = null;
954         missCountLk = null;
955         removalCountLk = null;
956         refreshCountLk = null;
957         addCountLk = null;
958         overflowCountLk = null;
959         buckets = null;
960         bucketLocks = null;
961         refreshFlags = null;
962         listeners = null;
963     }
964
965     /**
966      * clear the stats
967      */

968     public void clearStats() {
969         hitCount = 0;
970         missCount = 0;
971         removalCount = 0;
972         refreshCount = 0;
973         overflowCount = 0;
974         addCount = 0;
975     }
976
977     /** default CacheItem class implementation ***/
978     protected static class CacheItem {
979         int hashCode;
980         Object JavaDoc key;
981         Object JavaDoc value;
982         int size;
983     
984         CacheItem next;
985         
986         protected CacheItem(int hashCode, Object JavaDoc key, Object JavaDoc value, int size) {
987             this.hashCode = hashCode;
988             this.key = key;
989             this.value = value;
990             this.size = size;
991         }
992         
993         /**
994          * get the item's hashCode
995          */

996         protected int getHashCode() {
997             return hashCode;
998         }
999     
1000        /**
1001         * get the item's key
1002         */

1003        protected Object JavaDoc getKey() {
1004            return key;
1005        }
1006    
1007        /**
1008         * get the item's value
1009         */

1010        protected Object JavaDoc getValue() {
1011            return value;
1012        }
1013    
1014        /**
1015         * @return size of the entry in bytes
1016         * a value of -1 indicates unknown size
1017         */

1018        protected int getSize() {
1019            return size;
1020        }
1021    
1022        /**
1023         * refresh the item's value
1024         * @param value value to be updated
1025         * @param newSize of the field
1026         */

1027        protected Object JavaDoc refreshValue(Object JavaDoc value, int newSize) {
1028            Object JavaDoc oldValue = this.value;
1029            this.value = value;
1030            this.size = newSize;
1031    
1032            return oldValue;
1033        }
1034    
1035        public String JavaDoc toString() {
1036            return "key: " + key + "; value: " + value.toString();
1037        }
1038    }
1039}
1040
Popular Tags