KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > ejb > containers > 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 package com.sun.ejb.containers.util.cache;
25
26 import com.sun.appserv.util.cache.Cache;
27 import com.sun.appserv.util.cache.CacheListener;
28 import com.sun.appserv.util.cache.Constants;
29
30 import java.text.MessageFormat JavaDoc;
31
32 import java.util.ArrayList JavaDoc;
33 import java.util.Enumeration JavaDoc;
34 import java.util.Vector JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.HashMap JavaDoc;
37 import java.util.Properties JavaDoc;
38 import java.util.Iterator JavaDoc;
39 import java.util.ResourceBundle JavaDoc;
40
41 import com.sun.logging.LogDomains;
42
43 /**
44  * BaseCache
45  * Generic in-memory, abstract cache
46  */

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

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

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

109     public BaseCache() { }
110     
111     /**
112      * Sets all references to null. This method should be called
113      * at the end of this object's life cycle.
114      */

115     public void destroy() {
116         if ((listeners != null) && (buckets != null) && (bucketLocks != null)){
117             clear();
118             this.listeners.clear();
119         }
120         
121         this.entryCountLk = null;
122         this.hitCountLk = null;
123         this.missCountLk = null;
124         this.removalCountLk = null;
125         this.refreshCountLk = null;
126         this.addCountLk = null;
127         this.overflowCountLk = null;
128         this.buckets = null;
129         this.bucketLocks = null;
130         this.refreshFlags = null;
131         this.listeners = null;
132     }
133
134
135     /**
136      * initialize the cache
137      * @param maxEntries maximum number of entries expected in the cache
138      * @param props opaque list of properties for a given cache implementation
139      * @throws a generic Exception if the initialization failed
140      */

141     public void init(int maxEntries, Properties JavaDoc props) throws Exception JavaDoc {
142         init(maxEntries, DEFAULT_LOAD_FACTOR, props);
143     }
144     
145     /**
146      * initialize the cache
147      * @param maxEntries maximum number of entries expected in the cache
148      * @param loadFactor the load factor
149      * @param props opaque list of properties for a given cache implementation
150      * @throws a generic Exception if the initialization failed
151      */

152     public void init(int maxEntries, float loadFactor, Properties JavaDoc props) {
153
154         // web container logger
155
_rb = LogDomains.getLogger(LogDomains.UTIL_LOGGER).getResourceBundle();
156         
157         if (maxEntries <= 0) {
158             String JavaDoc msg = _rb.getString("cache.BaseCache.illegalMaxEntries");
159             
160             Integer JavaDoc obj = new Integer JavaDoc(maxEntries);
161             Object JavaDoc[] params = { obj };
162             msg = MessageFormat.format(msg, params);
163             
164             throw new IllegalArgumentException JavaDoc(msg);
165         }
166         
167         if (maxEntries > MAX_ENTRIES) {
168             maxEntries = MAX_ENTRIES;
169         }
170
171         this.maxEntries = maxEntries;
172
173         // find a power of 2 >= maxEntries
174
maxBuckets = 1;
175         while (maxBuckets < maxEntries) {
176             maxBuckets <<= 1;
177         }
178
179         /** initialize the threshold; a zero value for maxEntries
180          * implies no caching.
181          */

182         if (maxEntries != 0) {
183             threshold = (int)(maxEntries * loadFactor) + 1;
184         }
185
186         // create the cache and the bucket locks
187
entryCount = 0;
188         buckets = new CacheItem[maxBuckets];
189         bucketLocks = new Object JavaDoc[maxBuckets];
190         refreshFlags = new boolean[maxBuckets];
191
192         for (int i=0; i<maxBuckets; i++) {
193             buckets[i] = null;
194             bucketLocks[i] = new Object JavaDoc();
195             refreshFlags[i] = false;
196         }
197     }
198
199     /**
200      * add the cache module listener
201      * @param listener <code>CacheListener</code> implementation
202      */

203     public void addCacheListener(CacheListener listener) {
204         listeners.add(listener);
205     }
206     
207     /**
208      * Returns a hash code for non-null Object x.
209      * @See also <code>HashMap</code>
210      */

211     protected int hash(Object JavaDoc x) {
212         int h = x.hashCode();
213         return h - (h << 7); // i.e., -127 * h
214
}
215     
216     /**
217      * Check for equality of non-null reference x and possibly-null y.
218      */

219     protected boolean eq(Object JavaDoc x, Object JavaDoc y) {
220         return x == y || x.equals(y);
221     }
222     
223     /**
224      * increase the threshold
225      */

226     protected void handleOverflow() {
227         // just double the threshold; this may degenerate the cache.
228
threshold = (threshold * 2);
229         incrementOverflowCount();
230     }
231     
232     /**
233      * this item is just added to the cache
234      * @param item <code>CacheItem</code> that was created
235      * @return a overflow item; may be null
236      * Cache bucket is already synchronized by the caller
237      *
238      * Here, if cache is overflowing (i.e. reached threshold); this class
239      * simply makes the cache unbounded by raising the threshold. Subclasses
240      * are expected to provide a robust cache replacement algorithm.
241      *
242      * Subclasses should enhance this implemntation.
243      */

244     protected CacheItem itemAdded(CacheItem item) {
245         if (isThresholdReached()) {
246             handleOverflow();
247         }
248         return null;
249     }
250
251     /**
252      * this item is accessed
253      * @param item <code>CacheItem</code> accessed
254      *
255      * Cache bucket is already synchronized by the caller
256      */

257     protected void itemAccessed(CacheItem item) { }
258
259     /**
260      * item value has been refreshed
261      * @param item <code>CacheItem</code> that was refreshed
262      * @param oldSize size of the previous value that was refreshed
263      * Cache bucket is already synchronized by the caller
264      */

265     protected void itemRefreshed(CacheItem item, int oldSize) { }
266
267     /**
268      * item value has been removed from the cache
269      * @param item <code>CacheItem</code> that was just removed
270      *
271      * Cache bucket is already synchronized by the caller
272      */

273     protected void itemRemoved(CacheItem item) { }
274
275     /**
276      * Cannot find an item with the given key and hashCode
277      * @param key <code>Object</code> that is not found
278      * @param hashCode <code>int</code> its hashCode
279      *
280      * @returns the Object value associated with the item
281      * Cache bucket is already synchronized by the caller
282      */

283     protected Object JavaDoc loadValue(Object JavaDoc key, int hashCode) {
284         return null;
285     }
286
287     /**
288      * create new item
289      * @param hashCode for the entry
290      * @param key <code>Object</code> key
291      * @param value <code>Object</code> value
292      * @param size size in bytes of the item
293      * subclasses may override to provide their own CacheItem extensions
294      * e.g. one that permits persistence.
295      */

296     protected CacheItem createItem(int hashCode, Object JavaDoc key,
297                                         Object JavaDoc value, int size) {
298         return new CacheItem(hashCode, key, value, size);
299     }
300  
301     /**
302      * has cache reached its threshold
303      * @return true when the cache reached its threshold
304      */

305     protected boolean isThresholdReached() {
306         return (entryCount > threshold);
307     }
308
309     /**
310      * get the index of the item in the cache
311      * @param hashCode of the entry
312      * @return the index to be used in the cache
313      */

314     protected final int getIndex(int hashCode) {
315         return (hashCode & (maxBuckets - 1));
316     }
317
318     /**
319      * get the index of the item given a key
320      * @param key of the entry
321      * @return the index to be used in the cache
322      */

323     public final int getIndex(Object JavaDoc key) {
324         return getIndex(hash(key));
325     }
326
327     /**
328      * get the item stored at the key.
329      * @param key lookup key
330      * @returns the item stored at the key; null if not found.
331      */

332     public Object JavaDoc get(Object JavaDoc key) {
333         int hashCode = hash(key);
334
335         return get(hashCode, key);
336     }
337
338     /**
339      * get the item stored at the given pre-computed hash code and the key.
340      * @param key lookup key
341      * @returns the item stored at the key; null if not found.
342      */

343     public Object JavaDoc get(int hashCode, Object JavaDoc key) {
344
345         int index = getIndex(hashCode);
346         Object JavaDoc value;
347         CacheItem item = null;
348
349         synchronized (bucketLocks[index]) {
350             item = buckets[index];
351             
352             for (; item != null; item = item.next) {
353                 if ( (hashCode == item.hashCode) && eq(key, item.key) ) {
354                     break;
355                 }
356             }
357             
358             // update the stats in line
359
if (item != null) {
360                 value = item.getValue();
361                 itemAccessed(item);
362             }
363             else {
364                 value = loadValue(key, hashCode);
365             }
366         }
367         
368         if (item != null) {
369             incrementHitCount();
370         } else {
371             incrementMissCount();
372         }
373
374         return value;
375     }
376         
377     /**
378      * check if the cache contains the item at the key
379      * @param key lookup key
380      * @returns true if there is an item stored at the key; false if not.
381      */

382     public boolean contains(Object JavaDoc key) {
383         return (get(key) != null);
384     }
385     
386     /**
387      * get all the items stored at the key.
388      * @param key lookup key
389      * @returns an Iterator over the items with the given key.
390      */

391     public Iterator JavaDoc getAll(Object JavaDoc key) {
392         int hashCode = hash(key);
393         int index = getIndex(hashCode);
394
395         ArrayList JavaDoc valueList = new ArrayList JavaDoc(entryCount);
396         synchronized (bucketLocks[index]) {
397             CacheItem item = buckets[index];
398             
399             for (; item != null; item = item.next) {
400                 if ( (hashCode == item.hashCode) && eq(key, item.key) ) {
401                     incrementHitCount();
402                     valueList.add(item.getValue());
403                 }
404             }
405             
406         }
407
408         return valueList.iterator();
409     }
410
411     /**
412      * get an Iterator for the keys stored in the cache
413      * @returns an Iterator
414      */

415     public Iterator JavaDoc keys() {
416         ArrayList JavaDoc keyList = new ArrayList JavaDoc(entryCount);
417
418         for (int index=0; index < maxBuckets; index++) {
419             synchronized (bucketLocks[index]) {
420                 for (CacheItem item = buckets[index]; item != null;
421                      item = item.next) {
422                     keyList.add(item.key);
423                 }
424             }
425         }
426         
427         return keyList.iterator();
428     }
429     
430     /**
431      * get an Enumeration for the keys stored in the cache
432      * @returns an Enumeration
433      * XXX: should use Iterator which is based on Collections
434      */

435     public Enumeration JavaDoc elements() {
436         Vector JavaDoc keyList = new Vector JavaDoc();
437         
438         for (int index=0; index < maxBuckets; index++) {
439             synchronized (bucketLocks[index]) {
440                 for (CacheItem item = buckets[index]; item != null;
441                      item = item.next) {
442                     keyList.addElement(item.value);
443                 }
444             }
445         }
446         
447         return keyList.elements();
448     }
449     
450     /**
451      * get an Iterator for the values stored in the cache
452      * @returns an Iterator
453      */

454     public Iterator JavaDoc values() {
455         ArrayList JavaDoc valueList = new ArrayList JavaDoc(entryCount);
456         
457         for (int index=0; index < maxBuckets; index++) {
458             synchronized (bucketLocks[index]) {
459                 for (CacheItem item = buckets[index]; item != null;
460                      item = item.next) {
461                     valueList.add(item.value);
462                 }
463             }
464         }
465         
466         return valueList.iterator();
467     }
468     
469     /**
470      * cache the given value at the specified key and return previous value
471      * @param key lookup key
472      * @param object item value to be stored
473      * @returns the previous item stored at the key; null if not found.
474      */

475     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
476         int hashCode = hash(key);
477         
478         return _put(hashCode, key, value, -1, false);
479     }
480     
481     /**
482      * cache the given value at the specified key and return previous value
483      * @param key lookup key
484      * @param object item value to be stored
485      * @param size in bytes of the value being cached
486      * @returns the previous item stored at the key; null if not found.
487      */

488     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value, int size) {
489         int hashCode = hash(key);
490
491         return _put(hashCode, key, value, size, false);
492     }
493
494     /**
495      * add the given value to the cache at the specified key
496      * @param key lookup key
497      * @param object item value to be stored
498      */

499     public void add(Object JavaDoc key, Object JavaDoc value) {
500         int hashCode = hash(key);
501
502         _put(hashCode, key, value, -1, true);
503     }
504
505     /**
506      * add the given value with specified size to the cache at specified key
507      * @param key lookup key
508      * @param object item value to be stored
509      * @param size in bytes of the value being added
510      *
511      * This function is suitable for multi-valued keys.
512      */

513     public void add(Object JavaDoc key, Object JavaDoc value, int size) {
514         int hashCode = hash(key);
515
516         _put(hashCode, key, value, size, true);
517     }
518
519     /**
520      * cache the given value at the specified key and return previous value
521      * @param hashCode previously computed hashCode for the key
522      * @param key lookup key
523      * @param object item value to be stored
524      * @param size in bytes of the value being cached
525      * @param addValue treate this operation to add (default is to replace)
526      * @returns the previous item stored at the key; null if not found.
527      *
528      * Note: This can be used just to refresh the cached item as well, altho
529      * it may call trimCache() if the cache reached its threshold -- which is
530      * is probably not very intuitive.
531      */

532     protected Object JavaDoc _put(int hashCode, Object JavaDoc key,
533                           Object JavaDoc value, int size, boolean addValue) {
534         int index = getIndex(hashCode);
535         
536         CacheItem item, newItem = null, oldItem = null, overflow = null;
537         Object JavaDoc oldValue;
538         int oldSize = 0;
539
540         // lookup the item
541
synchronized (bucketLocks[index]) {
542             for (item = buckets[index]; item != null; item = item.next) {
543                 if ((hashCode == item.hashCode) && eq(key, item.key)) {
544
545                     oldItem = item;
546                     break;
547                 }
548             }
549
550             // if there was no item in the cache, insert the given item
551
if (addValue || oldItem == null) {
552                 newItem = createItem(hashCode, key, value, size);
553                 
554                 // add the item at the head of the bucket list
555
newItem.next = buckets[index];
556                 buckets[index] = newItem;
557                 
558                 oldValue = null;
559                 overflow = itemAdded(newItem);
560             } else {
561                 oldSize = oldItem.getSize();
562                 oldValue = oldItem.refreshValue(value, size);
563                 itemRefreshed(oldItem, oldSize);
564             }
565         }
566
567         if (newItem != null) {
568             incrementEntryCount();
569             incrementAddCount();
570             
571             // make sure we are are not crossing the threshold
572
if (overflow != null) {
573                 trimItem(overflow);
574             }
575         } else {
576             incrementRefreshCount();
577         }
578
579         return oldValue;
580     }
581
582     /**
583      * remove the item stored at the key.
584      * @param key lookup key
585      * @returns the item stored at the key; null if not found.
586      */

587     public Object JavaDoc remove(Object JavaDoc key) {
588         int hashCode = hash(key);
589
590         Object JavaDoc retVal = null;
591         CacheItem removed = _remove( hashCode, key, null);
592         
593         if (removed != null) {
594             retVal = removed.getValue();
595         }
596         return retVal;
597     }
598
599     /**
600      * remove the item stored at the key.
601      * @param hashCode a precomputed hashCode
602      * @param key lookup key
603      * @returns the item stored at the key; null if not found.
604      */

605     public Object JavaDoc remove(int hashCode, Object JavaDoc key) {
606         Object JavaDoc retVal = null;
607         CacheItem removed = _remove( hashCode, key, null);
608         
609         if (removed != null) {
610             retVal = removed.getValue();
611         }
612         return retVal;
613     }
614
615     /**
616      * remove the given value stored at the key; value-specific removals.
617      * @param key lookup key
618      * @param value to match (for a multi-valued keys)
619      * @returns the item stored at the key; null if not found.
620      */

621     public Object JavaDoc remove(Object JavaDoc key, Object JavaDoc value) {
622         int hashCode = hash(key);
623         
624         Object JavaDoc retVal = null;
625         CacheItem removed = _remove( hashCode, key, value);
626         
627         if (removed != null) {
628             retVal = removed.getValue();
629         }
630         return retVal;
631     }
632
633     /**
634      * remove the item stored at the key.
635      * @param hashCode a precomputed hashCode
636      * @param key lookup key
637      * @param value of the item to be matched
638      * @returns the item stored at the key; null if not found.
639      */

640     protected CacheItem _remove(int hashCode, Object JavaDoc key, Object JavaDoc value) {
641         int index = getIndex(hashCode);
642
643         CacheItem prev = null, item = null;
644
645         synchronized (bucketLocks[index]) {
646             for (item = buckets[index]; item != null; item = item.next) {
647                 if (hashCode == item.hashCode && key.equals(item.key)) {
648
649                     if (value == null || value == item.value) {
650
651                         if (prev == null) {
652                             buckets[index] = item.next;
653                         } else {
654                             prev.next = item.next;
655                         }
656                         item.next = null;
657                         
658                         itemRemoved(item);
659                         break;
660                     }
661                 }
662                 prev = item;
663             }
664         }
665         
666         if (item != null) {
667             decrementEntryCount();
668             incrementRemovalCount();
669             
670             incrementHitCount();
671         } else {
672             incrementMissCount();
673         }
674
675         return item;
676     }
677
678     /**
679      * remove the item stored at the key.
680      * @param item CacheItem to be removed
681      * @return the item stored at the key; null if not found.
682      */

683     protected CacheItem _removeItem(CacheItem ritem) {
684
685         int index = getIndex(ritem.hashCode);
686
687         CacheItem prev = null, item = null;
688         
689         synchronized (bucketLocks[index]) {
690             for (item = buckets[index]; item != null; item = item.next) {
691                 if (item == ritem) {
692                     if (prev == null) {
693                         buckets[index] = item.next;
694                     } else {
695                         prev.next = item.next;
696                     }
697                     item.next = null;
698                     break;
699                 }
700                 prev = item;
701             }
702         }
703         
704         if (item != null) {
705             decrementEntryCount();
706         }
707
708         return item;
709     }
710
711     /**
712      * remove all the item with the given key.
713      * @param key lookup key
714      */

715     public void removeAll(Object JavaDoc key) {
716         int hashCode = hash(key);
717         int index = getIndex(hashCode);
718
719         CacheItem prev = null, item = null;
720         ArrayList JavaDoc items = new ArrayList JavaDoc(entryCount);
721
722         synchronized (bucketLocks[index]) {
723             for (item = buckets[index]; item != null;
724                  item = item.next) {
725                 if (hashCode == item.hashCode && key.equals(item.key)) {
726                     if (prev == null) {
727                         buckets[index] = item.next;
728                     } else {
729                         prev.next = item.next;
730                     }
731                     item.next = null;
732                     
733                     decrementEntryCount();
734                     incrementRemovalCount();
735                     
736                     items.add(item);
737                 }
738                 prev = item;
739             }
740         }
741
742         // notify subclasses
743
for (int i = 0; i < items.size(); i++) {
744             itemRemoved((CacheItem)items.get(i));
745         }
746     }
747
748     /**
749      * trim the item from the cache and notify listeners
750      * @param item to be trimmed
751      */

752     protected void trimItem(CacheItem item) {
753         CacheItem removed = _removeItem(item);
754
755         if (removed != null) {
756             for (int i = 0; i < listeners.size(); i++) {
757                 CacheListener listener = (CacheListener) listeners.get(i);
758                 listener.trimEvent(removed.key, removed.value);
759             }
760         }
761     }
762
763     /**
764      * wait for a refresh on the object associated with the key
765      * @param key lookup key
766      * @returns true on successful notification, or false if there is
767      * no thread refreshing this entry.
768      */

769     public boolean waitRefresh(int index) {
770         synchronized (bucketLocks[index]) {
771             if (refreshFlags[index] == false) {
772                 refreshFlags[index] = true;
773                 return false;
774             }
775
776             // wait till refresh is finished
777
try {
778                 bucketLocks[index].wait();
779             } catch (InterruptedException JavaDoc ie) {}
780         }
781         return true;
782     }
783
784     /**
785      * notify threads waiting for a refresh on the object associated
786      * with the key
787      * @param key lookup key
788      */

789     public void notifyRefresh(int index) {
790         // notify other threads waiting for refresh
791
synchronized (bucketLocks[index]) {
792             refreshFlags[index] = false;
793             bucketLocks[index].notifyAll();
794         }
795     }
796     
797     /**
798      * clear all the entries from the cache.
799      * @returns the number of entries cleared from the cache
800      */

801     public int clear() {
802         
803         CacheItem item=null, next=null;
804         int count = 0;
805         
806         for (int index = 0; index < maxBuckets; index++) {
807             synchronized (bucketLocks[index]) {
808                 for (item = buckets[index]; item != null;
809                      item = item.next) {
810                     next = item.next;
811                     item.next = null;
812                     
813                     count++;
814                     decrementEntryCount();
815                     itemRemoved(item);
816                     
817                     if (entryCount == 0) {
818                         break;
819                     }
820                 }
821                 buckets[index] = null;
822             }
823         }
824         
825         return count;
826     }
827     
828     /**
829      * trim the expired entries from the cache.
830      * @param maxCount maximum number of invalid entries to trim
831      * specify Integer.MAX_VALUE to trim all timedout entries
832      *
833      * This call is to be scheduled by a thread managed by the container.
834      */

835     public void trimExpiredEntries(int maxCount) {}
836
837     /**
838      * get the number of entries in the cache
839      * @return the number of entries the cache currently holds
840      */

841     public int getEntryCount() {
842         return entryCount;
843     }
844
845     /*** methods for monitoring the cache ***/
846
847     /**
848      * is this cache empty?
849      * @returns true if the cache is empty; false otherwise.
850      */

851     public boolean isEmpty() {
852         return (entryCount == 0);
853     }
854
855     /**
856      * synchronized counter updates
857      */

858     protected final void incrementEntryCount() {
859         synchronized(entryCountLk) {
860             entryCount++;
861         }
862     }
863
864     protected final void decrementEntryCount() {
865         synchronized(entryCountLk) {
866             entryCount--;
867         }
868     }
869
870     protected final void incrementHitCount() {
871         synchronized (hitCountLk) {
872             hitCount++;
873         }
874     }
875
876     protected final void incrementMissCount() {
877         synchronized (missCountLk) {
878             missCount++;
879         }
880     }
881
882     protected final void incrementRemovalCount() {
883         synchronized (removalCountLk) {
884             removalCount++;
885         }
886     }
887
888     protected final void incrementRefreshCount() {
889         synchronized (refreshCountLk) {
890             refreshCount++;
891         }
892     }
893
894     protected final void incrementAddCount() {
895         synchronized (addCountLk) {
896             addCount++;
897         }
898     }
899
900     protected final void incrementOverflowCount() {
901         synchronized (overflowCountLk) {
902             overflowCount++;
903         }
904     }
905
906     /**
907      * get generic stats from subclasses
908      */

909
910     /**
911      * get the desired statistic counter
912      * @param key to corresponding stat
913      * @return an Object corresponding to the stat
914      * See also: Constant.java for the key
915      */

916     public Object JavaDoc getStatByName(String JavaDoc key) {
917         Object JavaDoc stat = null;
918
919         if (key == null)
920             return null;
921
922         if (key.equals(Constants.STAT_BASECACHE_MAX_ENTRIES))
923             stat = new Integer JavaDoc(maxEntries);
924         else if (key.equals(Constants.STAT_BASECACHE_THRESHOLD))
925             stat = new Integer JavaDoc(threshold);
926         else if (key.equals(Constants.STAT_BASECACHE_TABLE_SIZE))
927             stat = new Integer JavaDoc(maxBuckets);
928         else if (key.equals(Constants.STAT_BASECACHE_ENTRY_COUNT))
929             stat = new Integer JavaDoc(entryCount);
930         else if (key.equals(Constants.STAT_BASECACHE_HIT_COUNT))
931             stat = new Integer JavaDoc(hitCount);
932         else if (key.equals(Constants.STAT_BASECACHE_MISS_COUNT))
933             stat = new Integer JavaDoc(missCount);
934         else if (key.equals(Constants.STAT_BASECACHE_REMOVAL_COUNT))
935             stat = new Integer JavaDoc(removalCount);
936         else if (key.equals(Constants.STAT_BASECACHE_REFRESH_COUNT))
937             stat = new Integer JavaDoc(refreshCount);
938         else if (key.equals(Constants.STAT_BASECACHE_OVERFLOW_COUNT))
939             stat = new Integer JavaDoc(overflowCount);
940         else if (key.equals(Constants.STAT_BASECACHE_ADD_COUNT))
941             stat = new Integer JavaDoc(addCount);
942
943         return stat;
944     }
945
946     /**
947      * get the stats snapshot
948      * @return a Map of stats
949      * See also: Constant.java for the keys
950      */

951     public Map JavaDoc getStats() {
952         HashMap JavaDoc stats = new HashMap JavaDoc();
953
954         stats.put(Constants.STAT_BASECACHE_MAX_ENTRIES,
955                   new Integer JavaDoc(maxEntries));
956         stats.put(Constants.STAT_BASECACHE_THRESHOLD,
957                   new Integer JavaDoc(threshold));
958         stats.put(Constants.STAT_BASECACHE_TABLE_SIZE,
959                   new Integer JavaDoc(maxBuckets));
960         stats.put(Constants.STAT_BASECACHE_ENTRY_COUNT,
961                   new Integer JavaDoc(entryCount));
962         stats.put(Constants.STAT_BASECACHE_HIT_COUNT,
963                   new Integer JavaDoc(hitCount));
964         stats.put(Constants.STAT_BASECACHE_MISS_COUNT,
965                   new Integer JavaDoc(missCount));
966         stats.put(Constants.STAT_BASECACHE_REMOVAL_COUNT,
967                   new Integer JavaDoc(removalCount));
968         stats.put(Constants.STAT_BASECACHE_REFRESH_COUNT,
969                   new Integer JavaDoc(refreshCount));
970         stats.put(Constants.STAT_BASECACHE_OVERFLOW_COUNT,
971                   new Integer JavaDoc(overflowCount));
972         stats.put(Constants.STAT_BASECACHE_ADD_COUNT,
973                   new Integer JavaDoc(addCount));
974
975         return stats;
976     }
977
978     /**
979      * clear the stats
980      */

981     public void clearStats() {
982         hitCount = 0;
983         missCount = 0;
984         removalCount = 0;
985         refreshCount = 0;
986         overflowCount = 0;
987         addCount = 0;
988     }
989
990     /** default CacheItem class implementation ***/
991     protected static class CacheItem {
992         int hashCode;
993         Object JavaDoc key;
994         Object JavaDoc value;
995         int size;
996     
997         CacheItem next;
998         
999         protected CacheItem(int hashCode, Object JavaDoc key, Object JavaDoc value, int size) {
1000            this.hashCode = hashCode;
1001            this.key = key;
1002            this.value = value;
1003            this.size = size;
1004        }
1005        
1006        /**
1007         * get the item's hashCode
1008         */

1009        protected int getHashCode() {
1010            return hashCode;
1011        }
1012        
1013        /**
1014         * get the item's key
1015         */

1016        protected Object JavaDoc getKey() {
1017            return key;
1018        }
1019        
1020        /**
1021         * get the item's value
1022         */

1023        protected Object JavaDoc getValue() {
1024            return value;
1025        }
1026        
1027        /**
1028         * @return size of the entry in bytes
1029         * a value of -1 indicates unknown size
1030         */

1031        protected int getSize() {
1032            return size;
1033        }
1034    
1035        /**
1036         * refresh the item's value
1037         * @param value value to be updated
1038         * @param newSize of the field
1039         */

1040        protected Object JavaDoc refreshValue(Object JavaDoc value, int newSize) {
1041            Object JavaDoc oldValue = this.value;
1042            this.value = value;
1043            this.size = newSize;
1044    
1045            return oldValue;
1046        }
1047    
1048        public String JavaDoc toString() {
1049            return "key: " + key + "; value: " + value.toString();
1050        }
1051    }
1052}
1053
Popular Tags