alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (BaseCache.java)

This example Glassfish source code file (BaseCache.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

arraylist, arraylist, basecache, cacheitem, cacheitem, cachelistener, default_load_factor, hashmap, iterator, iterator, max_entries, object, object, text, util, vector

The Glassfish BaseCache.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.appserv.util.cache;

import com.sun.logging.LogDomains;

import java.text.MessageFormat;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Map;
import java.util.HashMap;
import java.util.Properties;
import java.util.Iterator;
import java.util.ResourceBundle;

/**
 * BaseCache
 * Generic in-memory, abstract cache 
 */
public class BaseCache implements Cache {
    
    /**
     * The resource bundle containing the localized message strings.
     */
    protected static ResourceBundle _rb = null;

    static final int MAX_ENTRIES = 1 << 30;
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    // maximum number of entries this cache may ever hold
	int maxEntries;

    // the number of cache entries in this cache
    protected int   entryCount;
    private Object  entryCountLk = new Object();

    /** threshold for the cache; once the threshold is reached
     *  entries are removed to accomodate newer inserts
     */
    protected int threshold = 0;

    // the number of cache hits
    private int     hitCount;
    private Object  hitCountLk = new Object();

    // the number of cache misses
    private int     missCount;
    private Object  missCountLk = new Object();

    // the number of cache item removals
    private int    removalCount;
    private Object removalCountLk = new Object();

    // the number of cache item refreshes
    private int     refreshCount;
    private Object  refreshCountLk = new Object();

    // the number of times an item was added to cache
    private int     addCount;
    private Object  addCountLk = new Object();

    // the number of times the cache overflowed
    private int     overflowCount;
    private Object  overflowCountLk = new Object();

    // table size
	protected int maxBuckets;

    // cache entries hash table
	protected CacheItem[] buckets;
    // bucket-wide locks
	protected Object[]    bucketLocks;

    // boolean status and locks for item thread-safe refreshes
	protected boolean[]   refreshFlags;

    protected ArrayList listeners = new ArrayList();

    /**
     * default constructor for the basic cache
     */
    public BaseCache() { }

    /**
     * initialize the cache
     * @param maxEntries maximum number of entries expected in the cache
     * @param props opaque list of properties for a given cache implementation
     * @throws a generic Exception if the initialization failed
     */
    public void init(int maxEntries, Properties props) throws Exception {
        init(maxEntries, DEFAULT_LOAD_FACTOR, props);
    }

    /**
     * initialize the cache
     * @param maxEntries maximum number of entries expected in the cache
     * @param loadFactor the load factor
     * @param props opaque list of properties for a given cache implementation
     * @throws a generic Exception if the initialization failed
     */
    public void init(int maxEntries, float loadFactor, Properties props) {

        // web container logger
        _rb = LogDomains.getLogger(BaseCache.class,LogDomains.UTIL_LOGGER).getResourceBundle();

        if (maxEntries <= 0) {
            String msg = _rb.getString("cache.BaseCache.illegalMaxEntries");

            Integer obj = Integer.valueOf(maxEntries);
            Object[] params = { obj };
            msg = MessageFormat.format(msg, params);

            throw new IllegalArgumentException(msg);
        }

        if (maxEntries > MAX_ENTRIES)
             maxEntries = MAX_ENTRIES;

        this.maxEntries = maxEntries;

        // find a power of 2 >= maxEntries
        maxBuckets = 1;
        while (maxBuckets < maxEntries)
            maxBuckets <<= 1;

        //Cannot have the loadfactor as a negative value
        if( loadFactor < 0 )
            loadFactor = 0;

        /** initialize the threshold; a zero value for maxEntries
         *  implies no caching.
         */
        if (maxEntries != 0) {
            threshold = (int)(maxEntries * loadFactor) + 1;
        }

        // create the cache and the bucket locks
        entryCount = 0;
       	buckets = new CacheItem[maxBuckets];
       	bucketLocks = new Object[maxBuckets];
        refreshFlags = new boolean[maxBuckets];

        for (int i=0; i<maxBuckets; i++) {
       		buckets[i] = null;
			bucketLocks[i] = new Object();
            refreshFlags[i] = false;
        }
    }

    /**
     * add the cache module listener
     * @param listener <code>CacheListener implementation
     */
    public void addCacheListener(CacheListener listener) {
        listeners.add(listener);
    }

    /**
     * Returns a hash code for non-null Object x.
     * @See also <code>HashMap
     */
    protected int hash(Object x) {
        int h = x.hashCode();
        return h - (h << 7);  // i.e., -127 * h
    }

    /** 
     * Check for equality of non-null reference x and possibly-null y. 
     */
    protected boolean eq(Object x, Object y) {
        return x == y || x.equals(y);
    }

    /**
     * increase the threshold
     */
    protected void handleOverflow() {
        // just double the threshold; this may degenerate the cache.
        threshold = (threshold * 2);
        incrementOverflowCount();
    }

    /**
     * this item is just added to the cache
     * @param item <code>CacheItem that was created
     * @return a overflow item; may be null
     * Cache bucket is already synchronized by the caller
     *
     * Here, if cache is overflowing (i.e. reached threshold); this class 
     * simply makes the cache unbounded by raising the threshold. Subclasses 
     * are expected to provide a robust cache replacement algorithm.
     *
     * Subclasses should enhance this implemntation. 
     */
    protected CacheItem itemAdded(CacheItem item) {
        if (isThresholdReached()) {
            handleOverflow();
        }
        return null;
    }

    /**
     * this item is accessed 
     * @param item <code>CacheItem accessed
     *
     * Cache bucket is already synchronized by the caller
     */
    protected void itemAccessed(CacheItem item) { }

    /**
     * item value has been refreshed
     * @param item <code>CacheItem that was refreshed
     * @param oldSize size of the previous value that was refreshed
     * Cache bucket is already synchronized by the caller
     */
    protected void itemRefreshed(CacheItem item, int oldSize) { }

    /**
     * item value has been removed from the cache
     * @param item <code>CacheItem that was just removed
     *
     * Cache bucket is already synchronized by the caller
     */
    protected void itemRemoved(CacheItem item) { }

    /**
     * Cannot find an item with the given key and hashCode
     * @param key <code>Object that is not found
     * @param hashCode <code>int its hashCode
     *
     * @returns the Object value associated with the item
     * Cache bucket is already synchronized by the caller
     */
    protected Object loadValue(Object key, int hashCode) { 
        return null;
    }

    /**
     * create new item
     * @param hashCode for the entry
     * @param key <code>Object key 
     * @param value <code>Object value
     * @param size size in bytes of the item
     * subclasses may override to provide their own CacheItem extensions
     * e.g. one that permits persistence.
     */
    protected CacheItem createItem(int hashCode, Object key, 
                                        Object value, int size) {
        return new CacheItem(hashCode, key, value, size);
    }
 
    /**
     * has cache reached its threshold
     * @return true when the cache reached its threshold
     */
    protected boolean isThresholdReached() {
        return (entryCount > threshold);
    }

    /** 
     * get the index of the item in the cache
     * @param hashCode of the entry
     * @return the index to be used in the cache
     */
    protected final int getIndex(int hashCode) {
        return (hashCode & (maxBuckets - 1));
    }

    /** 
     * get the index of the item given a key
     * @param key of the entry
     * @return the index to be used in the cache
     */
    public final int getIndex(Object key) {
        return getIndex(hash(key));
    }

    /**
     * get the item stored at the key.
     * @param key lookup key
     * @returns the item stored at the key; null if not found.
     */
    public Object get(Object key) {
        int hashCode = hash(key);

        return get(hashCode, key);
    }

    /**
     * get the item stored at the given pre-computed hash code and the key.
     * @param key lookup key
     * @returns the item stored at the key; null if not found.
     */
    public Object get(int hashCode, Object key) {

		int index = getIndex(hashCode);
        Object value;
        CacheItem item = null;

		synchronized (bucketLocks[index]) {
		    item = buckets[index];

			for (; item != null; item = item.next) {
				if ( (hashCode == item.hashCode) && eq(key, item.key) ) {
					break;
				}
			}

            // update the stats in line
            if (item != null) {
                value = item.getValue();
                itemAccessed(item);
            }
            else
                value = loadValue(key, hashCode);
		}

        if (item != null)
            incrementHitCount();
        else
            incrementMissCount();

        return value;
    }
        
    /**
     * check if the cache contains the item at the key
     * @param key lookup key
     * @returns true if there is an item stored at the key; false if not.
     */
    public boolean contains(Object key) {
    	return (get(key) != null);
    }
    
    /**
     * get all the items stored at the key.
     * @param key lookup key
     * @returns an Iterator over the items with the given key.
     */
    public Iterator getAll(Object key) {
        int hashCode = hash(key);
		int index = getIndex(hashCode);

        ArrayList valueList = new ArrayList(entryCount);
		synchronized (bucketLocks[index]) {
		    CacheItem item = buckets[index];

			for (; item != null; item = item.next) {
				if ( (hashCode == item.hashCode) && eq(key, item.key) ) {
                    incrementHitCount();
                    valueList.add(item.getValue());
				}
			}

		}

        return valueList.iterator();
    }

    /**
     * get an Iterator for the keys stored in the cache
     * @returns an Iterator
     */
    public Iterator keys() {
        ArrayList keyList = new ArrayList(entryCount);

        for (int index=0; index < maxBuckets; index++) {
            synchronized (bucketLocks[index]) {
                for (CacheItem item = buckets[index]; item != null; 
                                item = item.next) {
                    keyList.add(item.key);
                }
            }
        }

        return keyList.iterator();
    }

    /**
     * get an Enumeration for the keys stored in the cache
     * @returns an Enumeration
     * XXX: should use Iterator which is based on Collections
     */
    public Enumeration elements() {
        Vector keyList = new Vector();

        for (int index=0; index < maxBuckets; index++) {
            synchronized (bucketLocks[index]) {
                for (CacheItem item = buckets[index]; item != null; 
                                item = item.next) {
                    keyList.addElement(item.key);
                }
            }
        }

        return keyList.elements();
    }

    /**
     * get an Iterator for the values stored in the cache
     * @returns an Iterator
     */
    public Iterator values() {
        ArrayList valueList = new ArrayList(entryCount);

        for (int index=0; index < maxBuckets; index++) {
            synchronized (bucketLocks[index]) {
                for (CacheItem item = buckets[index]; item != null; 
                                item = item.next) {
                    valueList.add(item.value);
                }
            }
        }

        return valueList.iterator();
    }

    /**
    /**
     * cache the given value at the specified key and return previous value
     * @param key lookup key
     * @param object item value to be stored
     * @returns the previous item stored at the key; null if not found.
     */
    public Object put(Object key, Object value) {
        int hashCode = hash(key);

        return _put(hashCode, key, value, -1, false);
    }

    /**
     * cache the given value at the specified key and return previous value
     * @param key lookup key
     * @param object item value to be stored
     * @param size in bytes of the value being cached
     * @returns the previous item stored at the key; null if not found.
     */
    public Object put(Object key, Object value, int size) {
        int hashCode = hash(key);

        return _put(hashCode, key, value, size, false);
    }

    /**
     * add the given value to the cache at the specified key
     * @param key lookup key
     * @param object item value to be stored
     */
    public void add(Object key, Object value) {
        int hashCode = hash(key);

        _put(hashCode, key, value, -1, true);
    }

    /**
     * add the given value with specified size to the cache at specified key
     * @param key lookup key
     * @param object item value to be stored
     * @param size in bytes of the value being added
     *
     * This function is suitable for multi-valued keys.
     */
    public void add(Object key, Object value, int size) {
        int hashCode = hash(key);

        _put(hashCode, key, value, size, true);
    }

    /**
     * cache the given value at the specified key and return previous value
     * @param hashCode previously computed hashCode for the key
     * @param key lookup key
     * @param object item value to be stored
     * @param size in bytes of the value being cached
     * @param addValue treate this operation to add (default is to replace)
     * @returns the previous item stored at the key; null if not found.
     *
     * Note: This can be used just to refresh the cached item as well, altho
     * it may call trimCache() if the cache reached its threshold -- which is
     * is probably not very intuitive.
     */
    protected Object _put(int hashCode, Object key,
                            Object value, int size, boolean addValue) {
		int index = getIndex(hashCode);

		CacheItem item, newItem = null, oldItem = null, overflow = null;
        Object oldValue;
        int oldSize = 0;

        // lookup the item
		synchronized (bucketLocks[index]) {
			for (item = buckets[index]; item != null; item = item.next) {
				if ((hashCode == item.hashCode) && eq(key, item.key)) {

                    oldItem = item;
					break;
				}
			}

            // if there was no item in the cache, insert the given item
			if (addValue || oldItem == null) {
                newItem = createItem(hashCode, key, value, size); 
        
                // add the item at the head of the bucket list
			    newItem.next = buckets[index];
			    buckets[index] = newItem;

                oldValue = null;
                overflow = itemAdded(newItem);
			}
            else {
                oldSize = oldItem.getSize();
                oldValue = oldItem.refreshValue(value, size);
                itemRefreshed(oldItem, oldSize);
            }
		}

        if (newItem != null) {
            incrementEntryCount();
            incrementAddCount();

            // make sure we are are not crossing the threshold
            if (overflow != null)
                trimItem(overflow);
        }
        else
            incrementRefreshCount();

        return oldValue;
    }

    /**
     * remove the item stored at the key.
     * @param key lookup key
     * @returns the item stored at the key; null if not found.
     */
    public Object remove(Object key) {
        int hashCode = hash(key);

        Object retVal  = null;
        CacheItem removed = _remove( hashCode, key, null);
        
        if (removed != null)
            retVal = removed.getValue();
        return retVal;
    }

    /**
     * remove the item stored at the key.
     * @param hashCode a precomputed hashCode
     * @param key lookup key
     * @returns the item stored at the key; null if not found.
     */
    public Object remove(int hashCode, Object key) {
        Object retVal  = null;
        CacheItem removed = _remove( hashCode, key, null);
        
        if (removed != null)
            retVal = removed.getValue();
        return retVal;
    }

    /**
     * remove the given value stored at the key; value-specific removals.
     * @param key lookup key
     * @param value to match (for a multi-valued keys)
     * @returns the item stored at the key; null if not found.
     */
    public Object remove(Object key, Object value) {
        int hashCode = hash(key);

        Object retVal  = null;
        CacheItem removed = _remove( hashCode, key, value);
        
        if (removed != null)
            retVal = removed.getValue();
        return retVal;
    }

    /**
     * remove the item stored at the key.
     * @param hashCode a precomputed hashCode
     * @param key lookup key
     * @param value of the item to be matched 
     * @returns the item stored at the key; null if not found.
     */
    protected CacheItem _remove(int hashCode, Object key, Object value) {
		int index = getIndex(hashCode);

		CacheItem prev = null, item = null;

		synchronized (bucketLocks[index]) {
			for (item = buckets[index]; item != null; item = item.next) {
			    if (hashCode == item.hashCode && key.equals(item.key)) {

				    if (value == null || value == item.value) {

                        if (prev == null) {
                            buckets[index] = item.next;
                        } else  {
                            prev.next = item.next;
                        }
                        item.next = null;

                        itemRemoved(item);
                        break;
                    }
			    }
			    prev = item;
			}
        }
        
        if (item != null) {
            decrementEntryCount();
            incrementRemovalCount();

            incrementHitCount();
        } else
            incrementMissCount();

        return item;
    }

    /**
     * remove the item stored at the key.
     * @param item CacheItem to be removed
     * @return the item stored at the key; null if not found.
     */
    protected CacheItem _removeItem(CacheItem ritem) {

		int index = getIndex(ritem.hashCode);

		CacheItem prev = null, item = null;

		synchronized (bucketLocks[index]) {
			for (item = buckets[index]; item != null; item = item.next) {
			    if (item == ritem) {
                    if (prev == null) {
                        buckets[index] = item.next;
                    } else  {
                        prev.next = item.next;
                    }
                    item.next = null;
                    break;
			    }
			    prev = item;
			}
        }
        
        if (item != null) {
            decrementEntryCount();
        }

        return item;
    }

    /**
     * remove all the item with the given key.
     * @param key lookup key
     */
    public void removeAll(Object key) {
        int hashCode = hash(key);
		int index = getIndex(hashCode);

		CacheItem prev = null, item = null;
        ArrayList items = new ArrayList(entryCount);

		synchronized (bucketLocks[index]) {
			for (item = buckets[index]; item != null;
                                    item = item.next) {
			    if (hashCode == item.hashCode && key.equals(item.key)) {
                        if (prev == null) {
                            buckets[index] = item.next;
                        } else  {
                            prev.next = item.next;
                        }
                        item.next = null;
        
                        decrementEntryCount();
                        incrementRemovalCount();

                        items.add(item);
			    }
			    prev = item;
			}
        }

        // notify subclasses
        for (int i = 0; i < items.size(); i++) {
            itemRemoved((CacheItem)items.get(i));
        }
    }

    /**
     * trim the item from the cache and notify listeners
     * @param item to be trimmed
     */
    protected void trimItem(CacheItem item) {
        CacheItem removed = _removeItem(item);

        if (removed != null) {
            for (int i = 0; i < listeners.size(); i++) {
                CacheListener listener = (CacheListener) listeners.get(i);
                listener.trimEvent(removed.key, removed.value);
            }
        }
    }

    /**
     * wait for a refresh on the object associated with the key
     * @param key lookup key
     * @returns true on successful notification, or false if there is
     *  no thread refreshing this entry.
     */
    public boolean waitRefresh(int index) {
		synchronized (bucketLocks[index]) {
            if (refreshFlags[index] == false) {
                refreshFlags[index] = true;
                return false;
            }

            // wait till refresh is finished
            try {
                bucketLocks[index].wait();
            } catch (InterruptedException ie) {}
        }
        return true;
    }

    /**
     * notify threads waiting for a refresh on the object associated with the key
     * @param key lookup key
     */
    public void notifyRefresh(int index) {
        // notify other threads waiting for refresh
		synchronized (bucketLocks[index]) {
            refreshFlags[index] = false;
            bucketLocks[index].notifyAll();
        }
    }

    /**
     * clear all the entries from the cache.
     * @returns the number of entries cleared from the cache
     */
    public int clear() {
        
		CacheItem item=null, next=null;
        int count = 0;

        for (int index = 0; index < maxBuckets; index++) {
		    synchronized (bucketLocks[index]) {
			    for (item = buckets[index]; item != null; 
                                            item = item.next) {
                    next = item.next;
                    item.next = null;

                    count++;
                    decrementEntryCount();
                    itemRemoved(item);

                    if (entryCount == 0)
                        break;
			    }
                buckets[index] = null;
            }
        }


        return count;
    }

    /**
     * trim the expired entries from the cache.
     * @param maxCount maximum number of invalid entries to trim
     *        specify Integer.MAX_VALUE to trim all timedout entries
     *
     * This call is to be scheduled by a thread managed by the container.
     */
    public void trimExpiredEntries(int maxCount) {}

    /**
     * get the number of entries in the cache
     * @return the number of entries the cache currently holds
     */
    public int getEntryCount() {
        return entryCount;
    }

    /*** methods for monitoring the cache          ***/

    /**
     * is this cache empty?
     * @returns true if the cache is empty; false otherwise.
     */
    public boolean isEmpty() {
        return (entryCount == 0);
    }

    /**
     * synchronized counter updates
     */
    protected final void incrementEntryCount() {
        synchronized(entryCountLk) {
            entryCount++;
        }
    }

    protected final void decrementEntryCount() {
        synchronized(entryCountLk) {
            entryCount--;
        }
    }

    protected final void incrementHitCount() {
        synchronized (hitCountLk) {
            hitCount++;
        }
    }

    protected final void incrementMissCount() {
        synchronized (missCountLk) {
            missCount++;
        }
    }

    protected final void incrementRemovalCount() {
        synchronized (removalCountLk) {
            removalCount++;
        }
    }

    protected final void incrementRefreshCount() {
        synchronized (refreshCountLk) {
            refreshCount++;
        }
    }

    protected final void incrementAddCount() {
        synchronized (addCountLk) {
            addCount++;
        }
    }

    protected final void incrementOverflowCount() {
        synchronized (overflowCountLk) {
            overflowCount++;
        }
    }

    /**
     * get generic stats from subclasses 
     */

    /**
     * get the desired statistic counter
     * @param key to corresponding stat
     * @return an Object corresponding to the stat
     * See also: Constant.java for the key
     */
    public Object getStatByName(String key) {
        Object stat = null;

        if (key == null)
            return null;

        if (key.equals(Constants.STAT_BASECACHE_MAX_ENTRIES))
            stat = Integer.valueOf(maxEntries);
        else if (key.equals(Constants.STAT_BASECACHE_THRESHOLD))
            stat = Integer.valueOf(threshold);
        else if (key.equals(Constants.STAT_BASECACHE_TABLE_SIZE))
            stat = Integer.valueOf(maxBuckets);
        else if (key.equals(Constants.STAT_BASECACHE_ENTRY_COUNT))
            stat = Integer.valueOf(entryCount);
        else if (key.equals(Constants.STAT_BASECACHE_HIT_COUNT))
            stat = Integer.valueOf(hitCount);
        else if (key.equals(Constants.STAT_BASECACHE_MISS_COUNT))
            stat = Integer.valueOf(missCount);
        else if (key.equals(Constants.STAT_BASECACHE_REMOVAL_COUNT))
            stat = Integer.valueOf(removalCount);
        else if (key.equals(Constants.STAT_BASECACHE_REFRESH_COUNT))
            stat = Integer.valueOf(refreshCount);
        else if (key.equals(Constants.STAT_BASECACHE_OVERFLOW_COUNT))
            stat = Integer.valueOf(overflowCount);
        else if (key.equals(Constants.STAT_BASECACHE_ADD_COUNT))
            stat = Integer.valueOf(addCount);

        return stat;
    }

    /**
     * get the stats snapshot
     * @return a Map of stats
     * See also: Constant.java for the keys
     */
    public Map getStats() {
        HashMap stats = new HashMap();

        stats.put(Constants.STAT_BASECACHE_MAX_ENTRIES,
                  Integer.valueOf(maxEntries));
        stats.put(Constants.STAT_BASECACHE_THRESHOLD,
                  Integer.valueOf(threshold));
        stats.put(Constants.STAT_BASECACHE_TABLE_SIZE,
                  Integer.valueOf(maxBuckets));
        stats.put(Constants.STAT_BASECACHE_ENTRY_COUNT,
                  Integer.valueOf(entryCount));
        stats.put(Constants.STAT_BASECACHE_HIT_COUNT,
                  Integer.valueOf(hitCount));
        stats.put(Constants.STAT_BASECACHE_MISS_COUNT,
                  Integer.valueOf(missCount));
        stats.put(Constants.STAT_BASECACHE_REMOVAL_COUNT,
                  Integer.valueOf(removalCount));
        stats.put(Constants.STAT_BASECACHE_REFRESH_COUNT,
                  Integer.valueOf(refreshCount));
        stats.put(Constants.STAT_BASECACHE_OVERFLOW_COUNT,
                  Integer.valueOf(overflowCount));
        stats.put(Constants.STAT_BASECACHE_ADD_COUNT,
                  Integer.valueOf(addCount));

        return stats;
    }

    /**
     * Sets all references to null. This method should be called 
     * at the end of this object's life cycle.
     */
    public void destroy() {
        if ((listeners != null) && (buckets != null) && (bucketLocks != null)) {
            clear();
            listeners.clear();
        }

        entryCountLk     = null;
        hitCountLk       = null;
        missCountLk      = null;
        removalCountLk   = null;
        refreshCountLk   = null;
        addCountLk       = null;
        overflowCountLk  = null;
        buckets          = null;
        bucketLocks      = null;
        refreshFlags     = null;
        listeners        = null;
    }

    /**
     * clear the stats
     */
    public void clearStats() {
        hitCount = 0;
        missCount = 0;
        removalCount = 0;
        refreshCount = 0;
        overflowCount = 0;
        addCount = 0;
    }

    /** default CacheItem class implementation  ***/
    protected static class CacheItem {
        int hashCode;
        Object key;
        Object value;
        int size;
    
        CacheItem next;
        
        protected CacheItem(int hashCode, Object key, Object value, int size) {
            this.hashCode = hashCode;
            this.key = key;
            this.value = value;
            this.size = size;
        }
        
        /**
         * get the item's hashCode
         */
        protected int getHashCode() {
            return hashCode;
        }
    
        /**
         * get the item's key
         */
        protected Object getKey() {
            return key;
        }
    
        /**
         * get the item's value
         */
        protected Object getValue() {
            return value;
        }
    
        /**
         * @return size of the entry in bytes
         * a value of -1 indicates unknown size
         */
        protected int getSize() {
            return size;
        }
    
        /**
         * refresh the item's value
         * @param value value to be updated
         * @param newSize of the field
         */
        protected Object refreshValue(Object value, int newSize) {
            Object oldValue = this.value;
            this.value = value;
            this.size = newSize;
    
            return oldValue;
        }
    
        public String toString() {
            return "key: " + key + "; value: " + value.toString();
        }
    }
}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish BaseCache.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.