KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > util > TimedCachePolicy


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.util;
23
24 import java.util.ArrayList JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.Timer JavaDoc;
31 import java.util.TimerTask JavaDoc;
32
33 /** An implementation of a timed cache. This is a cache whose entries have a
34     limited lifetime with the ability to refresh their lifetime. The entries
35     managed by the cache implement the TimedCachePolicy.TimedEntry interface. If
36     an object inserted into the cache does not implement this interface, it will
37     be wrapped in a DefaultTimedEntry and will expire without the possibility of
38     refresh after getDefaultLifetime() seconds.
39
40     This is a lazy cache policy in that objects are not checked for expiration
41     until they are accessed.
42
43     @author <a HREF="mailto:Scott.Stark@jboss.org">Scott Stark</a>.
44     @version $Revision: 1958 $
45 */

46 public class TimedCachePolicy
47    extends TimerTask /* A legacy base class that is no longer used as this level */
48    implements CachePolicy
49 {
50    /** The interface that cache entries support.
51     */

52    public static interface TimedEntry
53    {
54       /** Initializes an entry with the current cache time. This is called when
55           the entry is first inserted into the cache so that entries do not
56           have to know the absolute system time.
57       */

58       public void init(long now);
59       
60       /** Is the entry still valid basis the current time
61           @return true if the entry is within its lifetime, false if it is expired.
62       */

63       public boolean isCurrent(long now);
64       
65       /** Attempt to extend the entry lifetime by refreshing it.
66           @return true if the entry was refreshed successfully, false otherwise.
67       */

68       public boolean refresh();
69       
70       /** Notify the entry that it has been removed from the cache.
71       */

72       public void destroy();
73
74       /** Get the value component of the TimedEntry. This may or may not
75           be the TimedEntry implementation.
76       */

77       public Object JavaDoc getValue();
78    }
79
80    protected static Timer JavaDoc resolutionTimer = new Timer JavaDoc(true);
81
82    /** The map of cached TimedEntry objects. */
83    protected Map JavaDoc entryMap;
84    /** The lifetime in seconds to use for objects inserted
85        that do not implement the TimedEntry interface. */

86    protected int defaultLifetime;
87    /** A flag indicating if entryMap should be synchronized */
88    protected boolean threadSafe;
89    /** The caches notion of the current time */
90    protected long now;
91    /** The resolution in seconds of the cach current time */
92    protected int resolution;
93    /** */
94    protected ResolutionTimer theTimer;
95
96    /** Creates a new TimedCachePolicy with a default entry lifetime of 30 mins
97        that does not synchronized access to its policy store and uses a 60
98        second resolution.
99    */

100    public TimedCachePolicy()
101    {
102       this(30*60, false, 0);
103    }
104    /** Creates a new TimedCachePolicy with the given default entry lifetime
105        that does not synchronized access to its policy store and uses a 60
106        second resolution.
107    */

108    public TimedCachePolicy(int defaultLifetime)
109    {
110       this(defaultLifetime, false, 0);
111    }
112    /** Creates a new TimedCachePolicy with the given default entry lifetime
113        that does/does not synchronized access to its policy store depending
114        on the value of threadSafe.
115        @param defaultLifetime - the lifetime in seconds to use for objects inserted
116        that do not implement the TimedEntry interface.
117        @param threadSafe - a flag indicating if the cach store should be synchronized
118        to allow correct operation under multi-threaded access. If true, the
119        cache store is synchronized. If false the cache store is unsynchronized and
120        the cache is not thread safe.
121        @param resolution - the resolution in seconds of the cache timer. A cache does
122        not query the system time on every get() invocation. Rather the cache
123        updates its notion of the current time every 'resolution' seconds.
124    */

125    public TimedCachePolicy(int defaultLifetime, boolean threadSafe, int resolution)
126    {
127       this.defaultLifetime = defaultLifetime;
128       this.threadSafe = threadSafe;
129       if( resolution <= 0 )
130          resolution = 60;
131       this.resolution = resolution;
132    }
133
134    // Service implementation ----------------------------------------------
135
/** Initializes the cache for use. Prior to this the cache has no store.
136     */

137    public void create()
138    {
139       if( threadSafe )
140          entryMap = Collections.synchronizedMap(new HashMap JavaDoc());
141       else
142          entryMap = new HashMap JavaDoc();
143       now = System.currentTimeMillis();
144    }
145    /** Schedules this with the class resolutionTimer Timer object for
146        execution every resolution seconds.
147    */

148    public void start()
149    {
150       theTimer = new ResolutionTimer();
151       resolutionTimer.scheduleAtFixedRate(theTimer, 0, 1000*resolution);
152    }
153    /** Stop cancels the resolution timer and flush()es the cache.
154     */

155    public void stop()
156    {
157       theTimer.cancel();
158       flush();
159    }
160    /** Clears the cache of all entries.
161     */

162    public void destroy()
163    {
164       entryMap.clear();
165    }
166
167    // --- Begin CachePolicy interface methods
168
/** Get the cache value for key if it has not expired. If the TimedEntry
169     is expired its destroy method is called and then removed from the cache.
170     @return the TimedEntry value or the original value if it was not an
171        instance of TimedEntry if key is in the cache, null otherwise.
172    */

173    public Object JavaDoc get(Object JavaDoc key)
174    {
175       TimedEntry entry = (TimedEntry) entryMap.get(key);
176       if( entry == null )
177          return null;
178
179       if( entry.isCurrent(now) == false )
180       { // Try to refresh the entry
181
if( entry.refresh() == false )
182          { // Failed, remove the entry and return null
183
entry.destroy();
184             entryMap.remove(key);
185             return null;
186          }
187       }
188       Object JavaDoc value = entry.getValue();
189       return value;
190    }
191    /** Get the cache value for key. This method does not check to see if
192        the entry has expired.
193        @return the TimedEntry value or the original value if it was not an
194        instancee of TimedEntry if key is in the cache, null otherwise.
195    */

196    public Object JavaDoc peek(Object JavaDoc key)
197    {
198       TimedEntry entry = (TimedEntry) entryMap.get(key);
199       Object JavaDoc value = null;
200       if( entry != null )
201          value = entry.getValue();
202       return value;
203    }
204    /** Insert a value into the cache. In order to have the cache entry
205        reshresh itself value would have to implement TimedEntry and
206        implement the required refresh() method logic.
207        @param key - the key for the cache entry
208        @param value - Either an instance of TimedEntry that will be inserted without
209        change, or an abitrary value that will be wrapped in a non-refreshing
210        TimedEntry.
211    */

212    public void insert(Object JavaDoc key, Object JavaDoc value)
213    {
214       if( entryMap.containsKey(key) )
215          throw new IllegalStateException JavaDoc("Attempt to insert duplicate entry");
216       TimedEntry entry = null;
217       if( (value instanceof TimedEntry) == false )
218       { // Wrap the value in a DefaultTimedEntry
219
entry = new DefaultTimedEntry(defaultLifetime, value);
220       }
221       else
222       {
223          entry = (TimedEntry) value;
224       }
225       entry.init(now);
226       entryMap.put(key, entry);
227    }
228    /** Remove the entry associated with key and call destroy on the entry
229     if found.
230     */

231    public void remove(Object JavaDoc key)
232    {
233       TimedEntry entry = (TimedEntry) entryMap.remove(key);
234       if( entry != null )
235          entry.destroy();
236    }
237    /** Remove all entries from the cache.
238     */

239    public void flush()
240    {
241       Map JavaDoc tmpMap = null;
242       synchronized( this )
243       {
244          tmpMap = entryMap;
245          if( threadSafe )
246             entryMap = Collections.synchronizedMap(new HashMap JavaDoc());
247          else
248             entryMap = new HashMap JavaDoc();
249       }
250
251       // Notify the entries of their removal
252
Iterator JavaDoc iter = tmpMap.values().iterator();
253       while( iter.hasNext() )
254       {
255          TimedEntry entry = (TimedEntry) iter.next();
256          entry.destroy();
257       }
258       tmpMap.clear();
259    }
260
261    public int size()
262    {
263       return entryMap.size();
264    }
265    // --- End CachePolicy interface methods
266

267    /** Get the list of keys for entries that are not expired.
268     *
269     * @return A List of the keys corresponding to valid entries
270     */

271    public List JavaDoc getValidKeys()
272    {
273       ArrayList JavaDoc validKeys = new ArrayList JavaDoc();
274       synchronized( entryMap )
275       {
276          Iterator JavaDoc iter = entryMap.entrySet().iterator();
277          while( iter.hasNext() )
278          {
279             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
280             TimedEntry value = (TimedEntry) entry.getValue();
281             if( value.isCurrent(now) == true )
282                validKeys.add(entry.getKey());
283          }
284       }
285       return validKeys;
286    }
287
288    /** Get the default lifetime of cache entries.
289     @return default lifetime in seconds of cache entries.
290     */

291    public int getDefaultLifetime()
292    {
293       return defaultLifetime;
294    }
295    /** Set the default lifetime of cache entries for new values added to the cache.
296     @param defaultLifetime - lifetime in seconds of cache values that do
297     not implement TimedEntry.
298     */

299    public synchronized void setDefaultLifetime(int defaultLifetime)
300    {
301       this.defaultLifetime = defaultLifetime;
302    }
303
304    /**
305     * Get the frequency of the current time snapshot.
306     * @return the current timer resolution in seconds.
307     */

308    public int getResolution()
309    {
310       return resolution;
311    }
312    /** Set the cache timer resolution
313     *
314     @param resolution - the resolution in seconds of the cache timer. A cache does
315     not query the system time on every get() invocation. Rather the cache
316     updates its notion of the current time every 'resolution' seconds.
317     */

318    public synchronized void setResolution(int resolution)
319    {
320       if( resolution <= 0 )
321          resolution = 60;
322       if( resolution != this.resolution )
323       {
324          this.resolution = resolution;
325          theTimer.cancel();
326          theTimer = new ResolutionTimer();
327          resolutionTimer.scheduleAtFixedRate(theTimer, 0, 1000*resolution);
328       }
329    }
330
331    /** The TimerTask run method. It updates the cache time to the
332        current system time.
333    */

334    public void run()
335    {
336       now = System.currentTimeMillis();
337    }
338
339    /** Get the cache time.
340        @return the cache time last obtained from System.currentTimeMillis()
341    */

342    public long currentTimeMillis()
343    {
344       return now;
345    }
346
347    /** Get the raw TimedEntry for key without performing any expiration check.
348        @return the TimedEntry value associated with key if one exists, null otherwise.
349    */

350    public TimedEntry peekEntry(Object JavaDoc key)
351    {
352       TimedEntry entry = (TimedEntry) entryMap.get(key);
353       return entry;
354    }
355
356    /** The default implementation of TimedEntry used to wrap non-TimedEntry
357        objects inserted into the cache.
358    */

359    static class DefaultTimedEntry implements TimedEntry
360    {
361       long expirationTime;
362       Object JavaDoc value;
363
364       DefaultTimedEntry(long lifetime, Object JavaDoc value)
365       {
366          this.expirationTime = 1000 * lifetime;
367          this.value = value;
368       }
369       public void init(long now)
370       {
371          expirationTime += now;
372       }
373       public boolean isCurrent(long now)
374       {
375          return expirationTime > now;
376       }
377       public boolean refresh()
378       {
379          return false;
380       }
381       public void destroy()
382       {
383       }
384       public Object JavaDoc getValue()
385       {
386          return value;
387       }
388    }
389
390    /**
391     
392     */

393    private class ResolutionTimer extends TimerTask
394    {
395       public void run()
396       {
397          TimedCachePolicy.this.run();
398       }
399    }
400 }
401
402
Popular Tags