1 package org.apache.fulcrum.cache.impl;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.List;
25
26 import org.apache.avalon.framework.activity.Disposable;
27 import org.apache.avalon.framework.activity.Initializable;
28 import org.apache.avalon.framework.configuration.Configurable;
29 import org.apache.avalon.framework.configuration.Configuration;
30 import org.apache.avalon.framework.configuration.ConfigurationException;
31 import org.apache.avalon.framework.logger.AbstractLogEnabled;
32 import org.apache.avalon.framework.thread.ThreadSafe;
33 import org.apache.fulcrum.cache.CachedObject;
34 import org.apache.fulcrum.cache.GlobalCacheService;
35 import org.apache.fulcrum.cache.ObjectExpiredException;
36 import org.apache.fulcrum.cache.RefreshableCachedObject;
37
38 import net.sf.ehcache.Cache;
39 import net.sf.ehcache.CacheManager;
40 import net.sf.ehcache.Element;
41
42
43
44
45
46
47
48
49 public class EHCacheService extends AbstractLogEnabled implements
50 GlobalCacheService, Runnable, Configurable, Disposable, Initializable, ThreadSafe
51 {
52
53
54
55
56 public static final long DEFAULT_CACHE_CHECK_FREQUENCY = 5000;
57
58
59
60
61 private long cacheCheckFrequency;
62
63
64
65
66 private String configFile;
67
68
69
70
71 private static final String DEFAULT_CACHE_NAME = "fulcrum";
72
73
74
75
76 private String cacheName;
77
78
79 private Thread refreshing;
80
81
82 private boolean continueThread;
83
84
85 private CacheManager cacheManager;
86
87
88 private Cache cache;
89
90 public EHCacheService()
91 {
92
93 }
94
95
96
97
98
99 @Override
100 public void configure(Configuration config) throws ConfigurationException
101 {
102 this.cacheCheckFrequency = config.getChild("cacheCheckFrequency")
103 .getValueAsLong(DEFAULT_CACHE_CHECK_FREQUENCY);
104 this.cacheName = config.getChild("cacheName").getValue(DEFAULT_CACHE_NAME);
105 this.configFile = config.getChild("configurationFile").getValue(null);
106 }
107
108
109
110
111 @Override
112 public void initialize() throws Exception
113 {
114 if (this.configFile == null)
115 {
116 this.cacheManager = new CacheManager();
117 this.cacheManager.addCache(this.cacheName);
118 }
119 else
120 {
121 this.cacheManager = new CacheManager(this.configFile);
122 }
123
124 this.cache = this.cacheManager.getCache(this.cacheName);
125
126
127 this.continueThread = true;
128 this.refreshing = new Thread(this);
129
130
131
132
133
134 this.refreshing.setDaemon(true);
135 this.refreshing.setName("EHCacheService Refreshing");
136 this.refreshing.start();
137
138 getLogger().debug("EHCacheService started!");
139 }
140
141
142
143
144 @Override
145 public void dispose()
146 {
147 this.continueThread = false;
148 this.refreshing.interrupt();
149
150 this.cacheManager.shutdown();
151 this.cacheManager = null;
152 this.cache = null;
153 getLogger().debug("EHCacheService stopped!");
154 }
155
156
157
158
159 @Override
160 public <T> void addObject(String objectId, CachedObject<T> object)
161 {
162 Element cacheElement = new Element(objectId, object);
163
164 if (object instanceof RefreshableCachedObject)
165 {
166 cacheElement.setEternal(true);
167 }
168 else
169 {
170 cacheElement.setEternal(false);
171 cacheElement.setTimeToLive((int)(object.getExpires() + 500) / 1000);
172 }
173
174 this.cache.put(cacheElement);
175 }
176
177
178
179
180 @Override
181 public void flushCache()
182 {
183 this.cache.removeAll();
184 }
185
186
187
188
189 @Override
190 public List<CachedObject<?>> getCachedObjects()
191 {
192 ArrayList<CachedObject<?>> values = new ArrayList<CachedObject<?>>();
193
194 for (String key : getKeys())
195 {
196 Element cachedElement = this.cache.get(key);
197
198 if (cachedElement != null)
199 {
200 values.add((CachedObject<?>)cachedElement.getObjectValue());
201 }
202 }
203
204 return values;
205 }
206
207
208
209
210 @SuppressWarnings("deprecation")
211 @Override
212 public int getCacheSize() throws IOException
213 {
214 return (int)this.cache.calculateInMemorySize();
215 }
216
217
218
219
220 @Override
221 public List<String> getKeys()
222 {
223 @SuppressWarnings("unchecked")
224 List<String> keysWithExpiryCheck = this.cache.getKeysWithExpiryCheck();
225 return keysWithExpiryCheck;
226 }
227
228
229
230
231 @Override
232 public int getNumberOfObjects()
233 {
234 return getKeys().size();
235 }
236
237
238
239
240 @Override
241 public <T> CachedObject<T> getObject(String objectId) throws ObjectExpiredException
242 {
243 Element cachedElement = this.cache.get(objectId);
244
245 if (cachedElement == null)
246 {
247
248 throw new ObjectExpiredException();
249 }
250
251 @SuppressWarnings("unchecked")
252 CachedObject<T> cachedObject = (CachedObject<T>)cachedElement.getObjectValue();
253
254 if (cachedObject.isStale())
255 {
256 if (cachedObject instanceof RefreshableCachedObject)
257 {
258 RefreshableCachedObject<?> refreshableCachedObject = (RefreshableCachedObject<?>) cachedObject;
259 if (refreshableCachedObject.isUntouched())
260 {
261
262 removeObject(objectId);
263 throw new ObjectExpiredException();
264 }
265
266
267 refreshableCachedObject.refresh();
268 if (refreshableCachedObject.isStale())
269 {
270
271 removeObject(objectId);
272 throw new ObjectExpiredException();
273 }
274 }
275 else
276 {
277
278 removeObject(objectId);
279 throw new ObjectExpiredException();
280 }
281 }
282
283 if (cachedObject instanceof RefreshableCachedObject)
284 {
285
286 RefreshableCachedObject<?> refreshableCachedObject = (RefreshableCachedObject<?>) cachedObject;
287 refreshableCachedObject.touch();
288 }
289
290 return cachedObject;
291 }
292
293
294
295
296 @Override
297 public void removeObject(String objectId)
298 {
299 this.cache.remove(objectId);
300 }
301
302
303
304
305
306 @Override
307 public void run()
308 {
309 while (this.continueThread)
310 {
311
312
313 try
314 {
315 Thread.sleep(this.cacheCheckFrequency);
316 }
317 catch (InterruptedException exc)
318 {
319 if (!this.continueThread)
320 {
321 return;
322 }
323 }
324
325 for (String key : getKeys())
326 {
327 Element cachedElement = this.cache.get(key);
328
329 if (cachedElement == null)
330 {
331 this.cache.remove(key);
332 continue;
333 }
334
335 Object object = cachedElement.getObjectValue();
336
337 if (object instanceof RefreshableCachedObject)
338 {
339 RefreshableCachedObject<?> refreshableObject = (RefreshableCachedObject<?>) object;
340 if (refreshableObject.isUntouched())
341 {
342 this.cache.remove(key);
343 }
344 else if (refreshableObject.isStale())
345 {
346 refreshableObject.refresh();
347 }
348 }
349 }
350 }
351 }
352 }