1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.ibatis.sqlmap.engine.cache;
17
18 import com.ibatis.common.logging.Log;
19 import com.ibatis.common.logging.LogFactory;
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.HashSet;
25 import java.util.Iterator;
26 import java.util.Properties;
27 import java.util.Set;
28
29
30
31
32 public class CacheModel implements ExecuteListener {
33
34
35 private static final Log log = LogFactory.getLog(CacheModel.class);
36
37
38 private static final int MAX_OBJECT_LOG_SIZE = 200;
39
40
41
42
43 public static final Object NULL_OBJECT = "SERIALIZABLE_NULL_OBJECT";
44
45
46 private int requests = 0;
47
48
49 private int hits = 0;
50
51
52 private static final long NO_FLUSH_INTERVAL = -99999;
53
54
55 private String id;
56
57
58 private boolean readOnly;
59
60
61 private boolean serialize;
62
63
64 private long lastFlush;
65
66
67 private long flushInterval;
68
69
70 private long flushIntervalSeconds;
71
72
73 private Set flushTriggerStatements;
74
75
76 private CacheController controller;
77
78
79 private String resource;
80
81
82
83
84 public CacheModel() {
85 this.flushInterval = NO_FLUSH_INTERVAL;
86 this.flushIntervalSeconds = NO_FLUSH_INTERVAL;
87 this.lastFlush = System.currentTimeMillis();
88 this.flushTriggerStatements = new HashSet();
89 }
90
91
92
93
94
95
96 public String getId() {
97 return id;
98 }
99
100
101
102
103
104
105
106 public void setId(String id) {
107 this.id = id;
108 }
109
110
111
112
113
114
115 public boolean isReadOnly() {
116 return readOnly;
117 }
118
119
120
121
122
123
124
125 public void setReadOnly(boolean readOnly) {
126 this.readOnly = readOnly;
127 }
128
129
130
131
132
133
134 public boolean isSerialize() {
135 return serialize;
136 }
137
138
139
140
141
142
143
144 public void setSerialize(boolean serialize) {
145 this.serialize = serialize;
146 }
147
148
149
150
151
152
153 public String getResource() {
154 return resource;
155 }
156
157
158
159
160
161
162
163 public void setResource(String resource) {
164 this.resource = resource;
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180 public void setCacheController(CacheController controller)
181 throws ClassNotFoundException, InstantiationException, IllegalAccessException {
182 this.controller = controller;
183 }
184
185
186
187
188
189
190 public long getFlushInterval() {
191 return flushInterval;
192 }
193
194
195
196
197
198
199 public long getFlushIntervalSeconds() {
200 return flushIntervalSeconds;
201 }
202
203
204
205
206
207
208
209 public void setFlushInterval(long flushInterval) {
210 this.flushInterval = flushInterval;
211 this.flushIntervalSeconds = flushInterval / 1000;
212 }
213
214
215
216
217
218
219
220 public void addFlushTriggerStatement(String statementName) {
221 flushTriggerStatements.add(statementName);
222 }
223
224
225
226
227
228
229 public Iterator getFlushTriggerStatementNames() {
230 return flushTriggerStatements.iterator();
231 }
232
233
234
235
236
237
238
239
240
241
242 public void onExecuteStatement(MappedStatement statement) {
243 flush();
244 }
245
246
247
248
249
250
251 public double getHitRatio() {
252 return (double) hits / (double) requests;
253 }
254
255
256
257
258
259
260
261 public void configure(Properties props) {
262 controller.setProperties(props);
263 }
264
265
266
267
268 public void flush() {
269 synchronized (this) {
270 controller.flush(this);
271 lastFlush = System.currentTimeMillis();
272 if (log.isDebugEnabled()) {
273 log("flushed", false, null);
274 }
275 }
276 }
277
278
279
280
281
282
283
284
285
286
287 public Object getObject(CacheKey key) {
288 Object value = null;
289 synchronized (this) {
290 if (flushInterval != NO_FLUSH_INTERVAL && System.currentTimeMillis() - lastFlush > flushInterval) {
291 flush();
292 }
293
294 value = controller.getObject(this, key);
295 if (serialize && !readOnly && (value != NULL_OBJECT && value != null)) {
296 try {
297 ByteArrayInputStream bis = new ByteArrayInputStream((byte[]) value);
298 ObjectInputStream ois = new ObjectInputStream(bis);
299 value = ois.readObject();
300 ois.close();
301 } catch (Exception e) {
302 throw new RuntimeException("Error caching serializable object. Be sure you're not attempting to use "
303 + "a serialized cache for an object that may be taking advantage of lazy loading. Cause: " + e, e);
304 }
305 }
306 requests++;
307 if (value != null) {
308 hits++;
309 }
310 if (log.isDebugEnabled()) {
311 if (value != null) {
312 log("retrieved object", true, value);
313 } else {
314 log("cache miss", false, null);
315 }
316 }
317 }
318 return value;
319 }
320
321
322
323
324
325
326
327
328
329 public void putObject(CacheKey key, Object value) {
330 if (null == value)
331 value = NULL_OBJECT;
332 synchronized (this) {
333 if (serialize && !readOnly && value != NULL_OBJECT) {
334 try {
335 ByteArrayOutputStream bos = new ByteArrayOutputStream();
336 ObjectOutputStream oos = new ObjectOutputStream(bos);
337 oos.writeObject(value);
338 oos.flush();
339 oos.close();
340 value = bos.toByteArray();
341 } catch (IOException e) {
342 throw new RuntimeException("Error caching serializable object. Cause: " + e, e);
343 }
344 }
345 controller.putObject(this, key, value);
346 if (log.isDebugEnabled()) {
347 log("stored object", true, value);
348 }
349 }
350 }
351
352
353
354
355
356
357 protected int getMaxObjectLogSize() {
358 return MAX_OBJECT_LOG_SIZE;
359 }
360
361
362
363
364
365
366
367
368
369
370
371
372 protected void log(String action, boolean addValue, Object cacheValue) {
373 StringBuilder output = new StringBuilder("Cache '");
374 output.append(getId());
375 output.append("': ");
376 output.append(action);
377 if (addValue) {
378 String cacheObjectStr = (cacheValue == null ? "null" : cacheValue.toString());
379 output.append(" '");
380 if (cacheObjectStr.length() < getMaxObjectLogSize()) {
381 output.append(cacheObjectStr);
382 } else {
383 output.append(cacheObjectStr.substring(1, getMaxObjectLogSize()));
384 output.append("...");
385 }
386 output.append("'");
387 }
388 log.debug(output.toString());
389 }
390
391
392
393
394
395
396
397 public void setControllerProperties(Properties cacheProps) {
398 controller.setProperties(cacheProps);
399 }
400 }