1 16 package com.ibatis.sqlmap.engine.cache; 17 18 import com.ibatis.common.exception.NestedRuntimeException; 19 import com.ibatis.common.resources.Resources; 20 import com.ibatis.sqlmap.engine.mapping.statement.ExecuteListener; 21 import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement; 22 23 import java.io.*; 24 import java.util.*; 25 26 29 public class CacheModel implements ExecuteListener { 30 31 private static final Map lockMap = new HashMap(); 32 36 public static final Object NULL_OBJECT = new Object (); 37 private final Object STATS_LOCK = new Object (); 38 private int requests = 0; 39 private int hits = 0; 40 41 44 private static final long NO_FLUSH_INTERVAL = -99999; 45 46 private String id; 47 48 private boolean readOnly; 49 private boolean serialize; 50 51 private long lastFlush; 52 private long flushInterval; 53 private long flushIntervalSeconds; 54 private Set flushTriggerStatements; 55 56 private CacheController controller; 57 58 private String resource; 59 60 63 public CacheModel() { 64 this.flushInterval = NO_FLUSH_INTERVAL; 65 this.flushIntervalSeconds = NO_FLUSH_INTERVAL; 66 this.lastFlush = System.currentTimeMillis(); 67 this.flushTriggerStatements = new HashSet(); 68 } 69 70 75 public String getId() { 76 return id; 77 } 78 79 84 public void setId(String id) { 85 this.id = id; 86 } 87 88 93 public boolean isReadOnly() { 94 return readOnly; 95 } 96 97 102 public void setReadOnly(boolean readOnly) { 103 this.readOnly = readOnly; 104 } 105 106 111 public boolean isSerialize() { 112 return serialize; 113 } 114 115 120 public void setSerialize(boolean serialize) { 121 this.serialize = serialize; 122 } 123 124 129 public String getResource() { 130 return resource; 131 } 132 133 138 public void setResource(String resource) { 139 this.resource = resource; 140 } 141 142 150 public void setControllerClassName(String implementation) 151 throws ClassNotFoundException , InstantiationException , IllegalAccessException { 152 Class clazz = Resources.classForName(implementation); 153 controller = (CacheController) Resources.instantiate(clazz); 154 } 155 156 161 public long getFlushInterval() { 162 return flushInterval; 163 } 164 165 170 public long getFlushIntervalSeconds() { 171 return flushIntervalSeconds; 172 } 173 174 179 public void setFlushInterval(long flushInterval) { 180 this.flushInterval = flushInterval; 181 this.flushIntervalSeconds = flushInterval / 1000; 182 } 183 184 190 public void addFlushTriggerStatement(String statementName) { 191 flushTriggerStatements.add(statementName); 192 } 193 194 199 public Iterator getFlushTriggerStatementNames() { 200 return flushTriggerStatements.iterator(); 201 } 202 203 213 public void onExecuteStatement(MappedStatement statement) { 214 flush(); 215 } 216 217 218 223 public double getHitRatio() { 224 return (double) hits / (double) requests; 225 } 226 227 232 public void configure(Properties props) { 233 controller.configure(props); 234 } 235 236 239 public void flush() { 240 lastFlush = System.currentTimeMillis(); 241 CacheKey key = new CacheKey(); 243 key.update(controller); 244 synchronized (getLock(key)) { 245 controller.flush(this); 246 } 247 } 248 249 257 public Object getObject(CacheKey key) { 258 synchronized (this) { 259 if (flushInterval != NO_FLUSH_INTERVAL 260 && System.currentTimeMillis() - lastFlush > flushInterval) { 261 flush(); 262 } 263 } 264 265 Object value = null; 266 synchronized (getLock(key)) { 267 value = controller.getObject(this, key); 268 } 269 270 if (serialize && !readOnly && (value != NULL_OBJECT && value != null)) { 271 try { 272 ByteArrayInputStream bis = new ByteArrayInputStream((byte[]) value); 273 ObjectInputStream ois = new ObjectInputStream(bis); 274 value = ois.readObject(); 275 ois.close(); 276 } catch (Exception e) { 277 throw new NestedRuntimeException("Error caching serializable object. Be sure you're not attempting to use " + 278 "a serialized cache for an object that may be taking advantage of lazy loading. Cause: " + e, e); 279 } 280 } 281 282 synchronized (STATS_LOCK) { 283 requests++; 284 if (value != null) { 285 hits++; 286 } 287 } 288 289 return value == NULL_OBJECT ? null : value; 290 291 } 292 293 299 public void putObject(CacheKey key, Object value) { 300 if (null == value) value = NULL_OBJECT; 301 if (serialize && !readOnly && value != NULL_OBJECT) { 302 try { 303 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 304 ObjectOutputStream oos = new ObjectOutputStream(bos); 305 oos.writeObject(value); 306 oos.flush(); 307 oos.close(); 308 value = bos.toByteArray(); 309 } catch (IOException e) { 310 throw new NestedRuntimeException("Error caching serializable object. Cause: " + e, e); 311 } 312 } 313 synchronized (getLock(key)) { 314 controller.putObject(this, key, value); 315 } 316 } 317 318 323 public synchronized final Object getLock(CacheKey key) { 324 int controllerId = System.identityHashCode(controller); 325 int keyHash = key.hashCode(); 326 Integer lockKey = new Integer (29 * controllerId + keyHash); 327 Object lock = lockMap.get(lockKey); 328 if (lock == null) { 329 lock = lockKey; lockMap.put(lockKey, lock); 331 } 332 return lock; 333 } 334 335 } 336 | Popular Tags |