001: /*
002: * XAPool: Open Source XA JDBC Pool
003: * Copyright (C) 2003 Objectweb.org
004: * Initial Developer: Lutris Technologies Inc.
005: * Contact: xapool-public@lists.debian-sf.objectweb.org
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
020: * USA
021: */
022: package org.enhydra.jdbc.util;
023:
024: import java.util.Hashtable;
025: import java.util.LinkedList;
026: import java.util.ArrayList;
027: import java.util.List;
028: import java.util.Iterator;
029: import java.util.Enumeration;
030:
031: /**
032: * Simple implementation of a cache, using Least Recently Used algorithm
033: * for discarding members when the cache fills up
034: */
035: public class LRUCache {
036: /** The cache */
037: private Hashtable cache = new Hashtable();
038: /** The linked list to keep track of least/most recently used */
039: private LinkedList lru = new LinkedList();
040: /** The maximum size of the cache */
041: private int maxSize;
042:
043: public Logger log;
044:
045: /**
046: * Constructor
047: */
048: public LRUCache(int maxSize) {
049: this .maxSize = maxSize;
050: }
051:
052: public int LRUSize() {
053: return lru.size();
054:
055: }
056:
057: public int cacheSize() {
058: return cache.size();
059:
060: }
061:
062: /**
063: * Puts a new object in the cache. If the cache is full, it removes
064: * the least recently used object. The new object becomes the most
065: * recently used object.
066: */
067: public void put(Object key, Object value) {
068: List removed = new ArrayList();
069: synchronized (this ) {
070: // make room if needed
071: while (cache.size() + 1 > maxSize) {
072: removed.add(removeLRU());
073: }
074: // remove the key from the list if it's in the cache already
075: Object cacheValue = cache.get(key);
076: if (cacheValue != null) {
077: if (cacheValue != value)
078: removed.add(cacheValue);
079:
080: lru.remove(key);
081: }
082: // the last item in the list is the most recently used
083: lru.addLast(key);
084: // put it in the actual cache
085: cache.put(key, value);
086: }
087: cleanupAll(removed);
088: }
089:
090: /**
091: * Gets an object from the cache. This object is set to be the
092: * most recenty used
093: */
094: public synchronized Object get(Object key) {
095: // check for existence in cache
096: if (!cache.containsKey(key)) {
097: return null;
098: }
099: // set to most recently used
100: lru.remove(key);
101: lru.addLast(key);
102: // return the object
103: return cache.get(key);
104: }
105:
106: /**
107: * Removes the object from the cache and the lru list
108: */
109: public synchronized Object remove(Object key) {
110: // check for existence in cache
111: if (!cache.containsKey(key)) {
112: return null;
113: }
114: // remove from lru list
115: lru.remove(key);
116: // remove from cache
117: Object obj = cache.remove(key);
118: return obj;
119: }
120:
121: private synchronized Object removeLRU() {
122: Object obj = cache.remove(lru.getFirst());
123: lru.removeFirst();
124: return obj;
125: }
126:
127: /**
128: * Resize the cache
129: */
130: public void resize(int newSize) {
131: if (newSize <= 0) {
132: return;
133: }
134: List removed = new ArrayList();
135: synchronized (this ) {
136: maxSize = newSize;
137: while (cache.size() > maxSize) {
138: removed.add(removeLRU());
139: }
140: }
141: cleanupAll(removed);
142: }
143:
144: private void cleanupAll(List removed) {
145: Iterator it = removed.iterator();
146: while (it.hasNext()) {
147: cleanupObject(it.next());
148: }
149: }
150:
151: /**
152: * Override this method to do special cleanup on an object,
153: * such as closing a statement or a connection
154: */
155: protected void cleanupObject(Object o) {
156: }
157:
158: public void cleanupAll() {
159: for (Enumeration enumeration = cache.keys(); enumeration
160: .hasMoreElements();) {
161:
162: Object o = remove(enumeration.nextElement());
163: cleanupObject(o);
164:
165: }
166: }
167:
168: public void setLogger(Logger alog) {
169: log = alog;
170: }
171: }
|