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.1 2007-08-24 22:17:29 ewestfal Exp $ 036 */ 037 public class ObjectCacheSoftImpl implements ObjectCache, Configurable 038 { 039 /** 040 * The static the cache map 041 */ 042 private static SoftHashMap cache = null; 043 044 /** 045 * The size of the cache 046 */ 047 private static int size = 10000; 048 049 /** 050 * Constructor called by ojb 051 * 052 * @param broker ignored parameter 053 * @param properties ignored parameter 054 */ 055 public ObjectCacheSoftImpl(PersistenceBroker broker, Properties properties) 056 { 057 if (cache == null) 058 { 059 OjbConfigurator.getInstance().configure(this); 060 cache = new SoftHashMap(size); 061 } 062 } 063 064 /** 065 * @see org.apache.ojb.broker.util.configuration.Configurable#configure(org.apache.ojb.broker.util.configuration.Configuration) 066 */ 067 public void configure(Configuration configuration) throws ConfigurationException 068 { 069 size = configuration.getInteger("ObjectCacheSoftImpl", size); 070 } 071 072 /** 073 * @see org.apache.ojb.broker.cache.ObjectCache#cache(org.apache.ojb.broker.Identity, java.lang.Object) 074 */ 075 public void cache(Identity oid, Object obj) 076 { 077 synchronized(cache) 078 { 079 cache.put(oid, obj); 080 } 081 } 082 083 public boolean cacheIfNew(Identity oid, Object obj) 084 { 085 synchronized(cache) 086 { 087 if(cache.get(oid) == null) 088 { 089 cache.put(oid, obj); 090 return true; 091 } 092 return false; 093 } 094 } 095 096 /** 097 * @see org.apache.ojb.broker.cache.ObjectCache#lookup(org.apache.ojb.broker.Identity) 098 */ 099 public Object lookup(Identity oid) 100 { 101 return cache.get(oid); 102 } 103 104 /** 105 * @see org.apache.ojb.broker.cache.ObjectCache#remove(org.apache.ojb.broker.Identity) 106 */ 107 public void remove(Identity oid) 108 { 109 synchronized(cache) 110 { 111 cache.remove(oid); 112 } 113 } 114 115 /** 116 * @see org.apache.ojb.broker.cache.ObjectCache#clear() 117 */ 118 public void clear() 119 { 120 cache.clear(); 121 } 122 123 /** 124 * Kind of map using SoftReference to store values 125 */ 126 public static final class SoftHashMap 127 { 128 /** 129 * The internal HashMap that will hold the SoftReference. 130 */ 131 private HashMap hash; 132 /** 133 * The FIFO list of hard references, order of last access. 134 */ 135 private LRUMap hardCacheMap; 136 /** 137 * Reference queue for cleared SoftReference objects. 138 */ 139 private ReferenceQueue queue; 140 141 /** 142 * Construct a new hash map with the specified size 143 * 144 * @param hardSize the maximum capacity of this map 145 */ 146 public SoftHashMap(final int hardSize) 147 { 148 hash = new HashMap(); 149 hardCacheMap = new LRUMap(hardSize); 150 queue = new ReferenceQueue(); 151 } 152 153 /** 154 * Put the key, value pair into the HashMap using a SoftValue object 155 * 156 * @param key the key 157 * @param value the value 158 * @return the old value 159 */ 160 public Object put(Object key, Object value) 161 { 162 //check null since hashtable doesn't support null key or null value 163 if (key == null || value == null) 164 { 165 return null; 166 } 167 processQueue(); // throw out garbage collected values first 168 hardCacheMap.put(key, value); 169 return hash.put(key, new SoftValue(value, key, queue)); 170 } 171 172 /** 173 * Retrieve the value associated to a given key 174 * 175 * @param key the key 176 * @return the value associated to this key 177 */ 178 public Object get(Object key) 179 { 180 // Check null since Hashtable doesn't support null key or null value 181 if (key == null) 182 { 183 return null; 184 } 185 Object result = null; 186 // We get the SoftReference represented by that key 187 SoftReference softRef = (SoftReference) hash.get(key); 188 if (softRef != null) 189 { 190 result = softRef.get(); 191 if (result == null) 192 { 193 // If the value has been garbage collected, remove the 194 // entry from the HashMap. 195 hash.remove(key); 196 } 197 else 198 { 199 if (!hardCacheMap.containsKey(key)) 200 { 201 hardCacheMap.put(key, result); 202 } 203 else 204 { 205 hardCacheMap.get(key); 206 } 207 } 208 } 209 return result; 210 } 211 212 /** 213 * Remove the entry for this key 214 * 215 * @param key the key 216 * @return the old value 217 */ 218 public Object remove(Object key) 219 { 220 processQueue(); // throw out garbage collected values first 221 Object retval = null; 222 Object value = hash.remove(key); 223 if (value != null) 224 { 225 if (value instanceof SoftValue) 226 { 227 retval = ((SoftValue) value).get(); 228 } 229 } 230 return retval; 231 } 232 233 /** 234 * Clear the map 235 */ 236 public void clear() 237 { 238 processQueue(); 239 hash.clear(); 240 hardCacheMap.clear(); 241 } 242 243 /** 244 * Class derived from SoftReference, used to 245 * store the key of the map. 246 */ 247 private class SoftValue extends SoftReference 248 { 249 /** 250 * the key 251 */ 252 private final Object key; // always make data member final 253 254 /** 255 * Create a SoftValue given the object, key and queue 256 * 257 * @param k the object 258 * @param key the key 259 * @param q the reference queue 260 */ 261 private SoftValue(final Object k, final Object key, final ReferenceQueue q) 262 { 263 super(k, q); 264 this.key = key; 265 } 266 } 267 268 /** 269 * Removes keys and objects that have been garbaged 270 */ 271 private void processQueue() 272 { 273 SoftValue sv; 274 while ((sv = (SoftValue) queue.poll()) != null) 275 { 276 hash.remove(sv.key); // we can access private data! 277 } 278 } 279 280 } 281 }