KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ha > framework > server > util > DistributedTimedCachePolicy


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.ha.framework.server.util;
23
24 import java.io.Serializable JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.Timer JavaDoc;
28 import java.util.TimerTask JavaDoc;
29 import javax.naming.InitialContext JavaDoc;
30
31 import org.jboss.ha.framework.interfaces.DistributedState;
32 import org.jboss.ha.framework.interfaces.HAPartition;
33 import org.jboss.logging.Logger;
34 import org.jboss.util.CachePolicy;
35
36 /** An implementation of a timed cache. This is a cache whose entries have a
37     limited lifetime with the ability to refresh their lifetime. The entries
38     managed by the cache implement the TimedCachePolicy.TimedEntry interface. If
39     an object inserted into the cache does not implement this interface, it will
40     be wrapped in a DefaultTimedEntry and will expire without the possibility of
41     refresh after getDefaultLifetime() seconds.
42
43     This is a lazy cache policy in that objects are not checked for expiration
44     until they are accessed.
45
46     @author <a HREF="mailto:Scott.Stark@jboss.org">Scott Stark</a>.
47     @version $Revision: 37459 $
48 */

49 public class DistributedTimedCachePolicy extends TimerTask JavaDoc
50    implements CachePolicy
51 {
52    /** The interface that cache entries support.
53     */

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

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

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

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

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

79       public Object JavaDoc getValue();
80    }
81
82    protected static Timer JavaDoc resolutionTimer = new Timer JavaDoc(true);
83    protected static Logger log = Logger.getLogger(DistributedTimedCachePolicy.class);
84
85    /** The map of cached TimedEntry objects. */
86    protected DistributedState entryMap;
87    protected String JavaDoc category;
88    protected String JavaDoc partitionName;
89    /** The lifetime in seconds to use for objects inserted
90        that do not implement the TimedEntry interface. */

91    protected int defaultLifetime;
92    /** The caches notion of the current time */
93    protected long now;
94    /** The resolution in seconds of the cach current time */
95    protected int resolution;
96
97    /** Creates a new TimedCachePolicy with the given default entry lifetime
98        that does not synchronized access to its policy store and uses a 60
99        second resolution.
100    */

101    public DistributedTimedCachePolicy(String JavaDoc category, String JavaDoc partitionName,
102       int defaultLifetime)
103    {
104       this(category, partitionName, defaultLifetime, 0);
105    }
106    /** Creates a new TimedCachePolicy with the given default entry lifetime
107     that does/does not synchronized access to its policy store depending
108     on the value of threadSafe.
109     @param category the name of the catetegory used in the DistributedState
110     access calls.
111     @param partitionName the name of the HAPartition who's replicated
112     state service will be used as the cache store.
113     @param defaultLifetime the lifetime in seconds to use for objects inserted
114     that do not implement the TimedEntry interface.
115     @param resolution the resolution in seconds of the cache timer. A cache does
116     not query the system time on every get() invocation. Rather the cache
117     updates its notion of the current time every 'resolution' seconds.
118     @see DistributedState
119    */

120    public DistributedTimedCachePolicy(String JavaDoc category, String JavaDoc partitionName,
121       int defaultLifetime, int resolution)
122    {
123       this.category = category;
124       this.partitionName = partitionName;
125       this.defaultLifetime = defaultLifetime;
126       if( resolution <= 0 )
127          resolution = 60;
128       this.resolution = resolution;
129    }
130
131    // Service implementation ----------------------------------------------
132
/** Initializes the cache for use. Prior to this the cache has no store.
133     */

134    public void create() throws Exception JavaDoc
135    {
136       // Lookup the parition
137
InitialContext JavaDoc ctx = new InitialContext JavaDoc();
138       String JavaDoc jndiName = "/HAPartition/" + partitionName;
139       HAPartition partition = (HAPartition) ctx.lookup(jndiName);
140       this.entryMap = partition.getDistributedStateService();
141       log.debug("Obtained DistributedState from partition="+partitionName);
142       now = System.currentTimeMillis();
143    }
144    /** Schedules this with the class resolutionTimer Timer object for
145        execution every resolution seconds.
146    */

147    public void start()
148    {
149       resolutionTimer.scheduleAtFixedRate(this, 0, 1000*resolution);
150    }
151    /** Stop cancels the resolution timer and flush()es the cache.
152     */

153    public void stop()
154    {
155       super.cancel();
156    }
157    /** Clears the cache of all entries.
158     */

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

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

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

217    public void insert(Object JavaDoc key, Object JavaDoc value)
218    {
219       Serializable JavaDoc skey = (Serializable JavaDoc) key;
220       TimedEntry entry = (TimedEntry) entryMap.get(category, skey);
221       if( entry != null )
222          throw new IllegalStateException JavaDoc("Attempt to insert duplicate entry");
223       if( (value instanceof TimedEntry) == false )
224       { // Wrap the value in a DefaultTimedEntry
225
Serializable JavaDoc svalue = (Serializable JavaDoc) value;
226          entry = new DefaultTimedEntry(defaultLifetime, svalue);
227       }
228       else
229       {
230          entry = (TimedEntry) value;
231       }
232
233       entry.init(now);
234       try
235       {
236          entryMap.set(category, skey, entry);
237       }
238       catch(Exception JavaDoc e)
239       {
240          log.error("Failed to set entry", e);
241       }
242    }
243
244    /** Remove the entry associated with key and call destroy on the entry
245     if found.
246     */

247    public void remove(Object JavaDoc key)
248    {
249       Serializable JavaDoc skey = (Serializable JavaDoc) key;
250       try
251       {
252          TimedEntry entry = (TimedEntry) entryMap.remove(category, skey);
253          if( entry != null )
254             entry.destroy();
255       }
256       catch(Exception JavaDoc e)
257       {
258          log.error("Failed to remove entry", e);
259       }
260    }
261    /** Remove all entries from the cache.
262     */

263    public void flush()
264    {
265       Collection JavaDoc keys = entryMap.getAllKeys(category);
266       // Notify the entries of their removal
267
Iterator JavaDoc iter = keys.iterator();
268       while( iter.hasNext() )
269       {
270          Serializable JavaDoc key = (Serializable JavaDoc) iter.next();
271          TimedEntry entry = (TimedEntry) entryMap.get(category, key);
272          entry.destroy();
273       }
274    }
275
276    public int size()
277    {
278       return entryMap.getAllKeys(category).size();
279    }
280    // --- End CachePolicy interface methods
281

282    /** Get the default lifetime of cache entries.
283     @return default lifetime in seconds of cache entries.
284     */

285    public int getDefaultLifetime()
286    {
287       return defaultLifetime;
288    }
289    /** Set the default lifetime of cache entries for new values added to the cache.
290     @param defaultLifetime lifetime in seconds of cache values that do
291     not implement TimedEntry.
292     */

293    public void setDefaultLifetime(int defaultLifetime)
294    {
295       this.defaultLifetime = defaultLifetime;
296    }
297
298    /** The TimerTask run method. It updates the cache time to the
299        current system time.
300    */

301    public void run()
302    {
303       now = System.currentTimeMillis();
304    }
305
306    /** Get the cache time.
307        @return the cache time last obtained from System.currentTimeMillis()
308    */

309    public long currentTimeMillis()
310    {
311       return now;
312    }
313
314    /** Get the raw TimedEntry for key without performing any expiration check.
315        @return the TimedEntry value associated with key if one exists, null otherwise.
316    */

317    public TimedEntry peekEntry(Object JavaDoc key)
318    {
319       Serializable JavaDoc skey = (Serializable JavaDoc) key;
320       TimedEntry entry = (TimedEntry) entryMap.get(category, skey);
321       return entry;
322    }
323
324    /** The default implementation of TimedEntry used to wrap non-TimedEntry
325        objects inserted into the cache.
326    */

327    static class DefaultTimedEntry implements TimedEntry
328    {
329       long expirationTime;
330       Serializable JavaDoc value;
331
332       DefaultTimedEntry(long lifetime, Serializable JavaDoc value)
333       {
334          this.expirationTime = 1000 * lifetime;
335          this.value = value;
336       }
337       public void init(long now)
338       {
339          expirationTime += now;
340       }
341       public boolean isCurrent(long now)
342       {
343          return expirationTime > now;
344       }
345       public boolean refresh()
346       {
347          return false;
348       }
349       public void destroy()
350       {
351       }
352       public Object JavaDoc getValue()
353       {
354          return value;
355       }
356    }
357 }
358
Popular Tags