KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > turbine > services > cache > TurbineGlobalCacheService


1 package org.apache.turbine.services.cache;
2
3 /*
4  * Copyright 2001-2004 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License")
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18
19 import java.io.ByteArrayOutputStream JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.ObjectOutputStream JavaDoc;
22
23 import java.util.Enumeration JavaDoc;
24 import java.util.Hashtable JavaDoc;
25 import java.util.Vector JavaDoc;
26
27 import org.apache.commons.configuration.Configuration;
28
29 import org.apache.turbine.services.InitializationException;
30 import org.apache.turbine.services.TurbineBaseService;
31
32 /**
33  * This Service functions as a Global Cache. A global cache is a good
34  * place to store items that you may need to access often but don't
35  * necessarily need (or want) to fetch from the database everytime. A
36  * good example would be a look up table of States that you store in a
37  * database and use throughout your application. Since information
38  * about States doesn't change very often, you could store this
39  * information in the Global Cache and decrease the overhead of
40  * hitting the database everytime you need State information.
41  *
42  * The following properties are needed to configure this service:<br>
43  *
44  * <code><pre>
45  * services.GlobalCacheService.classname=org.apache.turbine.services.cache.TurbineGlobalCacheService
46  * services.GlobalCacheService.cache.initial.size=20
47  * services.GlobalCacheService.cache.check.frequency=5000
48  * </pre></code>
49  *
50  * <dl>
51  * <dt>classname</dt><dd>the classname of this service</dd>
52  * <dt>cache.initial.size</dt><dd>Initial size of hash table use to store cached
53  objects. If this property is not present, the default value is 20</dd>
54  * <dt>cache.check.frequency</dt><dd>Cache check frequency in Millis (1000
55  Millis = 1 second). If this property is not present, the default value is 5000</dd>
56  * </dl>
57  *
58  * @author <a HREF="mailto:mbryson@mont.mindspring.com">Dave Bryson</a>
59  * @author <a HREF="mailto:jon@clearink.com">Jon S. Stevens</a>
60  * @author <a HREF="mailto:john@zenplex.com">John Thorhauer</a>
61  * @author <a HREF="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
62  * @version $Id: TurbineGlobalCacheService.java,v 1.10.2.2 2004/05/20 03:05:19 seade Exp $
63  */

64 public class TurbineGlobalCacheService
65         extends TurbineBaseService
66         implements GlobalCacheService,
67         Runnable JavaDoc
68 {
69     /**
70      * Initial size of hash table
71      * Value must be > 0.
72      * Default = 20
73      */

74     public static final int DEFAULT_INITIAL_CACHE_SIZE = 20;
75
76     /**
77      * The property for the InitalCacheSize
78      */

79     public static final String JavaDoc INITIAL_CACHE_SIZE = "cache.initial.size";
80
81     /**
82      * The property for the Cache check frequency
83      */

84     public static final String JavaDoc CACHE_CHECK_FREQUENCY = "cache.check.frequency";
85
86     /**
87      * Cache check frequency in Millis (1000 Millis = 1 second).
88      * Value must be > 0.
89      * Default = 5 seconds
90      */

91     public static final long DEFAULT_CACHE_CHECK_FREQUENCY = 5000; // 5 seconds
92

93     /** The cache. **/
94     private Hashtable JavaDoc cache = null;
95
96     /** cacheCheckFrequency (default - 5 seconds) */
97     private long cacheCheckFrequency = DEFAULT_CACHE_CHECK_FREQUENCY;
98
99     /**
100      * Constructor.
101      */

102     public TurbineGlobalCacheService()
103     {
104     }
105
106     /**
107      * Called the first time the Service is used.
108      */

109     public void init()
110             throws InitializationException
111     {
112         int cacheInitialSize = DEFAULT_INITIAL_CACHE_SIZE;
113         Configuration conf = getConfiguration();
114         if (conf != null)
115         {
116             try
117             {
118                 cacheInitialSize = conf.getInt(INITIAL_CACHE_SIZE, DEFAULT_INITIAL_CACHE_SIZE);
119                 if (cacheInitialSize <= 0)
120                 {
121                     throw new IllegalArgumentException JavaDoc(INITIAL_CACHE_SIZE + " must be >0");
122                 }
123                 cacheCheckFrequency = conf.getLong(CACHE_CHECK_FREQUENCY, DEFAULT_CACHE_CHECK_FREQUENCY);
124                 if (cacheCheckFrequency <= 0)
125                 {
126                     throw new IllegalArgumentException JavaDoc(CACHE_CHECK_FREQUENCY + " must be >0");
127                 }
128             }
129             catch (Exception JavaDoc x)
130             {
131                 throw new InitializationException(
132                         "Failed to initialize TurbineGlobalCacheService", x);
133             }
134         }
135
136         try
137         {
138             cache = new Hashtable JavaDoc(cacheInitialSize);
139
140             // Start housekeeping thread.
141
Thread JavaDoc housekeeping = new Thread JavaDoc(this);
142             // Indicate that this is a system thread. JVM will quit only when there
143
// are no more active user threads. Settings threads spawned internally
144
// by Turbine as daemons allows commandline applications using Turbine
145
// to terminate in an orderly manner.
146
housekeeping.setDaemon(true);
147             housekeeping.start();
148
149             setInit(true);
150         }
151         catch (Exception JavaDoc e)
152         {
153             throw new InitializationException(
154                     "TurbineGlobalCacheService failed to initialize", e);
155         }
156     }
157
158     /**
159      * Returns an item from the cache. RefreshableCachedObject will be
160      * refreshed if it is expired and not untouched.
161      *
162      * @param id The key of the stored object.
163      * @return The object from the cache.
164      * @exception ObjectExpiredException when either the object is
165      * not in the cache or it has expired.
166      */

167     public CachedObject getObject(String JavaDoc id)
168             throws ObjectExpiredException
169     {
170         CachedObject obj = null;
171         
172         obj = (CachedObject) cache.get(id);
173
174         if (obj == null)
175         {
176             // Not in the cache.
177
throw new ObjectExpiredException();
178         }
179
180         if (obj.isStale())
181         {
182             if (obj instanceof RefreshableCachedObject)
183             {
184                 RefreshableCachedObject rco = (RefreshableCachedObject) obj;
185                 if (rco.isUntouched())
186                 // Do not refresh an object that has exceeded TimeToLive
187
throw new ObjectExpiredException();
188                 // Refresh Object
189
rco.refresh();
190                 if (rco.isStale())
191                 // Object is Expired.
192
throw new ObjectExpiredException();
193             }
194             else
195             {
196                 // Expired.
197
throw new ObjectExpiredException();
198             }
199         }
200
201         if (obj instanceof RefreshableCachedObject)
202         {
203             // notify it that it's being accessed.
204
RefreshableCachedObject rco = (RefreshableCachedObject) obj;
205             rco.touch();
206         }
207
208         return obj;
209     }
210
211     /**
212      * Adds an object to the cache.
213      *
214      * @param id The key to store the object by.
215      * @param o The object to cache.
216      */

217     public void addObject(String JavaDoc id,
218                           CachedObject o)
219     {
220         // If the cache already contains the key, remove it and add
221
// the fresh one.
222
if (cache.containsKey(id))
223         {
224             cache.remove(id);
225         }
226         cache.put(id, o);
227     }
228
229     /**
230      * Removes an object from the cache.
231      *
232      * @param id The String id for the object.
233      */

234     public void removeObject(String JavaDoc id)
235     {
236         cache.remove(id);
237     }
238
239     /**
240      * Circle through the cache and remove stale objects. Frequency
241      * is determined by the cacheCheckFrequency property.
242      */

243     public void run()
244     {
245         while (true)
246         {
247             // Sleep for amount of time set in cacheCheckFrequency -
248
// default = 5 seconds.
249
try
250             {
251                 Thread.sleep(cacheCheckFrequency);
252             }
253             catch (InterruptedException JavaDoc exc)
254             {
255             }
256
257             clearCache();
258         }
259     }
260
261     /**
262      * Iterate through the cache and remove or refresh stale objects.
263      */

264     public void clearCache()
265     {
266         Vector JavaDoc refreshThese = new Vector JavaDoc(20);
267         // Sync on this object so that other threads do not
268
// change the Hashtable while enumerating over it.
269
synchronized (this)
270         {
271             for (Enumeration JavaDoc e = cache.keys(); e.hasMoreElements();)
272             {
273                 String JavaDoc key = (String JavaDoc) e.nextElement();
274                 CachedObject co = (CachedObject) cache.get(key);
275                 if (co instanceof RefreshableCachedObject)
276                 {
277                     RefreshableCachedObject rco = (RefreshableCachedObject) co;
278                     if (rco.isUntouched())
279                         cache.remove(key);
280                     else if (rco.isStale())
281                     // Do refreshing outside of sync block so as not
282
// to prolong holding the lock on this object
283
refreshThese.addElement(key);
284                 }
285                 else if (co.isStale())
286                 {
287                     cache.remove(key);
288                 }
289             }
290         }
291
292         for (Enumeration JavaDoc e = refreshThese.elements(); e.hasMoreElements();)
293         {
294             String JavaDoc key = (String JavaDoc) e.nextElement();
295             CachedObject co = (CachedObject) cache.get(key);
296             RefreshableCachedObject rco = (RefreshableCachedObject) co;
297             rco.refresh();
298         }
299     }
300
301     /**
302      * Returns the number of objects currently stored in the cache
303      *
304      * @return int number of object in the cache
305      */

306     public int getNumberOfObjects()
307     {
308         return cache.size();
309     }
310
311     /**
312      * Returns the current size of the cache.
313      *
314      * @return int representing current cache size in number of bytes
315      */

316     public int getCacheSize()
317             throws IOException JavaDoc
318     {
319         ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
320         ObjectOutputStream JavaDoc out = new ObjectOutputStream JavaDoc(baos);
321         out.writeObject(cache);
322         out.flush();
323         //
324
// Subtract 4 bytes from the length, because the serialization
325
// magic number (2 bytes) and version number (2 bytes) are
326
// both written to the stream before the object
327
//
328
int objectsize = baos.toByteArray().length - 4;
329         return objectsize;
330     }
331
332     /**
333      * Flush the cache of all objects.
334      */

335     public void flushCache()
336     {
337
338         synchronized (this)
339         {
340             for (Enumeration JavaDoc e = cache.keys(); e.hasMoreElements();)
341             {
342                 String JavaDoc key = (String JavaDoc) e.nextElement();
343                 cache.remove(key);
344             }
345         }
346     }
347 }
348
Popular Tags