001: package org.apache.ojb.broker.cache;
002:
003: /* Copyright 2004-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import java.lang.ref.ReferenceQueue;
019: import java.lang.ref.SoftReference;
020: import java.util.HashMap;
021: import java.util.Properties;
022:
023: import org.apache.commons.collections.LRUMap;
024: import org.apache.ojb.broker.Identity;
025: import org.apache.ojb.broker.PersistenceBroker;
026: import org.apache.ojb.broker.util.configuration.Configurable;
027: import org.apache.ojb.broker.util.configuration.Configuration;
028: import org.apache.ojb.broker.util.configuration.ConfigurationException;
029: import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator;
030:
031: /**
032: * A global {@link ObjectCache} implementation.
033: *
034: * @author matthew.baird
035: * @version $Id: ObjectCacheSoftImpl.java,v 1.7.2.2 2005/12/21 22:24:15 tomdz Exp $
036: */
037: public class ObjectCacheSoftImpl implements ObjectCache, Configurable {
038: /**
039: * The static the cache map
040: */
041: private static SoftHashMap cache = null;
042:
043: /**
044: * The size of the cache
045: */
046: private static int size = 10000;
047:
048: /**
049: * Constructor called by ojb
050: *
051: * @param broker ignored parameter
052: * @param properties ignored parameter
053: */
054: public ObjectCacheSoftImpl(PersistenceBroker broker,
055: Properties properties) {
056: if (cache == null) {
057: OjbConfigurator.getInstance().configure(this );
058: cache = new SoftHashMap(size);
059: }
060: }
061:
062: /**
063: * @see org.apache.ojb.broker.util.configuration.Configurable#configure(org.apache.ojb.broker.util.configuration.Configuration)
064: */
065: public void configure(Configuration configuration)
066: throws ConfigurationException {
067: size = configuration.getInteger("ObjectCacheSoftImpl", size);
068: }
069:
070: /**
071: * @see org.apache.ojb.broker.cache.ObjectCache#cache(org.apache.ojb.broker.Identity, java.lang.Object)
072: */
073: public void cache(Identity oid, Object obj) {
074: synchronized (cache) {
075: cache.put(oid, obj);
076: }
077: }
078:
079: public boolean cacheIfNew(Identity oid, Object obj) {
080: synchronized (cache) {
081: if (cache.get(oid) == null) {
082: cache.put(oid, obj);
083: return true;
084: }
085: return false;
086: }
087: }
088:
089: /**
090: * @see org.apache.ojb.broker.cache.ObjectCache#lookup(org.apache.ojb.broker.Identity)
091: */
092: public Object lookup(Identity oid) {
093: return cache.get(oid);
094: }
095:
096: /**
097: * @see org.apache.ojb.broker.cache.ObjectCache#remove(org.apache.ojb.broker.Identity)
098: */
099: public void remove(Identity oid) {
100: synchronized (cache) {
101: cache.remove(oid);
102: }
103: }
104:
105: /**
106: * @see org.apache.ojb.broker.cache.ObjectCache#clear()
107: */
108: public void clear() {
109: cache.clear();
110: }
111:
112: /**
113: * Kind of map using SoftReference to store values
114: */
115: public static final class SoftHashMap {
116: /**
117: * The internal HashMap that will hold the SoftReference.
118: */
119: private HashMap hash;
120: /**
121: * The FIFO list of hard references, order of last access.
122: */
123: private LRUMap hardCacheMap;
124: /**
125: * Reference queue for cleared SoftReference objects.
126: */
127: private ReferenceQueue queue;
128:
129: /**
130: * Construct a new hash map with the specified size
131: *
132: * @param hardSize the maximum capacity of this map
133: */
134: public SoftHashMap(final int hardSize) {
135: hash = new HashMap();
136: hardCacheMap = new LRUMap(hardSize);
137: queue = new ReferenceQueue();
138: }
139:
140: /**
141: * Put the key, value pair into the HashMap using a SoftValue object
142: *
143: * @param key the key
144: * @param value the value
145: * @return the old value
146: */
147: public Object put(Object key, Object value) {
148: //check null since hashtable doesn't support null key or null value
149: if (key == null || value == null) {
150: return null;
151: }
152: processQueue(); // throw out garbage collected values first
153: hardCacheMap.put(key, value);
154: return hash.put(key, new SoftValue(value, key, queue));
155: }
156:
157: /**
158: * Retrieve the value associated to a given key
159: *
160: * @param key the key
161: * @return the value associated to this key
162: */
163: public Object get(Object key) {
164: // Check null since Hashtable doesn't support null key or null value
165: if (key == null) {
166: return null;
167: }
168: Object result = null;
169: // We get the SoftReference represented by that key
170: SoftReference softRef = (SoftReference) hash.get(key);
171: if (softRef != null) {
172: result = softRef.get();
173: if (result == null) {
174: // If the value has been garbage collected, remove the
175: // entry from the HashMap.
176: hash.remove(key);
177: } else {
178: if (!hardCacheMap.containsKey(key)) {
179: hardCacheMap.put(key, result);
180: } else {
181: hardCacheMap.get(key);
182: }
183: }
184: }
185: return result;
186: }
187:
188: /**
189: * Remove the entry for this key
190: *
191: * @param key the key
192: * @return the old value
193: */
194: public Object remove(Object key) {
195: processQueue(); // throw out garbage collected values first
196: Object retval = null;
197: Object value = hash.remove(key);
198: if (value != null) {
199: if (value instanceof SoftValue) {
200: retval = ((SoftValue) value).get();
201: }
202: }
203: return retval;
204: }
205:
206: /**
207: * Clear the map
208: */
209: public void clear() {
210: processQueue();
211: hash.clear();
212: hardCacheMap.clear();
213: }
214:
215: /**
216: * Class derived from SoftReference, used to
217: * store the key of the map.
218: */
219: private class SoftValue extends SoftReference {
220: /**
221: * the key
222: */
223: private final Object key; // always make data member final
224:
225: /**
226: * Create a SoftValue given the object, key and queue
227: *
228: * @param k the object
229: * @param key the key
230: * @param q the reference queue
231: */
232: private SoftValue(final Object k, final Object key,
233: final ReferenceQueue q) {
234: super (k, q);
235: this .key = key;
236: }
237: }
238:
239: /**
240: * Removes keys and objects that have been garbaged
241: */
242: private void processQueue() {
243: SoftValue sv;
244: while ((sv = (SoftValue) queue.poll()) != null) {
245: hash.remove(sv.key); // we can access private data!
246: }
247: }
248:
249: }
250: }
|