KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > mina > util > ExpiringMap


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. 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,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  *
19  */

20 package org.apache.mina.util;
21
22 import java.util.Collection JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.Set JavaDoc;
25 import java.util.concurrent.ConcurrentHashMap JavaDoc;
26 import java.util.concurrent.CopyOnWriteArrayList JavaDoc;
27 import java.util.concurrent.locks.ReadWriteLock JavaDoc;
28 import java.util.concurrent.locks.ReentrantReadWriteLock JavaDoc;
29
30 /**
31  * A map with expiration.
32  *
33  * @author The Apache Directory Project (mina-dev@directory.apache.org)
34  */

35 public class ExpiringMap<K, V> implements Map JavaDoc<K, V> {
36     public static final int DEFAULT_TIME_TO_LIVE = 60;
37
38     public static final int DEFAULT_EXPIRATION_INTERVAL = 1;
39
40     private static volatile int expirerCount = 1;
41
42     private final ConcurrentHashMap JavaDoc<K, ExpiringObject> delegate;
43
44     private final CopyOnWriteArrayList JavaDoc<ExpirationListener> expirationListeners;
45
46     private final Expirer expirer;
47
48     public ExpiringMap() {
49         this(DEFAULT_TIME_TO_LIVE, DEFAULT_EXPIRATION_INTERVAL);
50     }
51
52     public ExpiringMap(int timeToLive) {
53         this(timeToLive, DEFAULT_EXPIRATION_INTERVAL);
54     }
55
56     public ExpiringMap(int timeToLive, int expirationInterval) {
57         this(new ConcurrentHashMap JavaDoc<K, ExpiringObject>(),
58                 new CopyOnWriteArrayList JavaDoc<ExpirationListener>(), timeToLive,
59                 expirationInterval);
60     }
61
62     private ExpiringMap(ConcurrentHashMap JavaDoc<K, ExpiringObject> delegate,
63             CopyOnWriteArrayList JavaDoc<ExpirationListener> expirationListeners,
64             int timeToLive, int expirationInterval) {
65         this.delegate = delegate;
66         this.expirationListeners = expirationListeners;
67
68         this.expirer = new Expirer();
69         expirer.setTimeToLive(timeToLive);
70         expirer.setExpirationInterval(expirationInterval);
71     }
72
73     public V put(K key, V value) {
74         ExpiringObject answer = delegate.put(key, new ExpiringObject(key,
75                 value, System.currentTimeMillis()));
76         if (answer == null) {
77             return null;
78         }
79
80         return answer.getValue();
81     }
82
83     public V get(Object JavaDoc key) {
84         ExpiringObject object = delegate.get(key);
85
86         if (object != null) {
87             object.setLastAccessTime(System.currentTimeMillis());
88
89             return object.getValue();
90         }
91
92         return null;
93     }
94
95     public V remove(Object JavaDoc key) {
96         ExpiringObject answer = delegate.remove(key);
97         if (answer == null) {
98             return null;
99         }
100
101         return answer.getValue();
102     }
103
104     public boolean containsKey(Object JavaDoc key) {
105         return delegate.containsKey(key);
106     }
107
108     public boolean containsValue(Object JavaDoc value) {
109         return delegate.containsValue(value);
110     }
111
112     public int size() {
113         return delegate.size();
114     }
115
116     public boolean isEmpty() {
117         return delegate.isEmpty();
118     }
119
120     public void clear() {
121         delegate.clear();
122     }
123
124     @Override JavaDoc
125     public int hashCode() {
126         return delegate.hashCode();
127     }
128
129     public Set JavaDoc<K> keySet() {
130         return delegate.keySet();
131     }
132
133     @Override JavaDoc
134     public boolean equals(Object JavaDoc obj) {
135         return delegate.equals(obj);
136     }
137
138     public void putAll(Map JavaDoc<? extends K, ? extends V> inMap) {
139         for (Entry<? extends K, ? extends V> e : inMap.entrySet()) {
140             this.put(e.getKey(), e.getValue());
141         }
142     }
143
144     public Collection JavaDoc<V> values() {
145         throw new UnsupportedOperationException JavaDoc();
146     }
147
148     public Set JavaDoc<Map.Entry JavaDoc<K, V>> entrySet() {
149         throw new UnsupportedOperationException JavaDoc();
150     }
151
152     public void addExpirationListener(ExpirationListener<? extends V> listener) {
153         expirationListeners.add(listener);
154     }
155
156     public void removeExpirationListener(
157             ExpirationListener<? extends V> listener) {
158         expirationListeners.remove(listener);
159     }
160
161     public Expirer getExpirer() {
162         return expirer;
163     }
164
165     public int getExpirationInterval() {
166         return expirer.getExpirationInterval();
167     }
168
169     public int getTimeToLive() {
170         return expirer.getTimeToLive();
171     }
172
173     public void setExpirationInterval(int expirationInterval) {
174         expirer.setExpirationInterval(expirationInterval);
175     }
176
177     public void setTimeToLive(int timeToLive) {
178         expirer.setTimeToLive(timeToLive);
179     }
180
181     private class ExpiringObject {
182         private K key;
183
184         private V value;
185
186         private long lastAccessTime;
187
188         private ReadWriteLock JavaDoc lastAccessTimeLock = new ReentrantReadWriteLock JavaDoc();
189
190         ExpiringObject(K key, V value, long lastAccessTime) {
191             if (value == null) {
192                 throw new IllegalArgumentException JavaDoc(
193                         "An expiring object cannot be null.");
194             }
195
196             this.key = key;
197             this.value = value;
198             this.lastAccessTime = lastAccessTime;
199         }
200
201         public long getLastAccessTime() {
202             lastAccessTimeLock.readLock().lock();
203
204             try {
205                 return lastAccessTime;
206             } finally {
207                 lastAccessTimeLock.readLock().unlock();
208             }
209         }
210
211         public void setLastAccessTime(long lastAccessTime) {
212             lastAccessTimeLock.writeLock().lock();
213
214             try {
215                 this.lastAccessTime = lastAccessTime;
216             } finally {
217                 lastAccessTimeLock.writeLock().unlock();
218             }
219         }
220
221         public K getKey() {
222             return key;
223         }
224
225         public V getValue() {
226             return value;
227         }
228
229         @Override JavaDoc
230         public boolean equals(Object JavaDoc obj) {
231             return value.equals(obj);
232         }
233
234         @Override JavaDoc
235         public int hashCode() {
236             return value.hashCode();
237         }
238     }
239
240     public class Expirer implements Runnable JavaDoc {
241         private ReadWriteLock JavaDoc stateLock = new ReentrantReadWriteLock JavaDoc();
242
243         private long timeToLiveMillis;
244
245         private long expirationIntervalMillis;
246
247         private boolean running = false;
248
249         private final Thread JavaDoc expirerThread;
250
251         public Expirer() {
252             expirerThread = new Thread JavaDoc(this, "ExpiringMapExpirer-"
253                     + (expirerCount++));
254             expirerThread.setDaemon(true);
255         }
256
257         public void run() {
258             while (running) {
259                 processExpires();
260
261                 try {
262                     Thread.sleep(expirationIntervalMillis);
263                 } catch (InterruptedException JavaDoc e) {
264                 }
265             }
266         }
267
268         private void processExpires() {
269             long timeNow = System.currentTimeMillis();
270
271             for (ExpiringObject o : delegate.values()) {
272
273                 if (timeToLiveMillis <= 0)
274                     continue;
275
276                 long timeIdle = timeNow - o.getLastAccessTime();
277
278                 if (timeIdle >= timeToLiveMillis) {
279                     delegate.remove(o.getKey());
280
281                     for (ExpirationListener<V> listener : expirationListeners) {
282                         listener.expired(o.getValue());
283                     }
284                 }
285             }
286         }
287
288         public void startExpiring() {
289             stateLock.writeLock().lock();
290
291             try {
292                 if (!running) {
293                     running = true;
294                     expirerThread.start();
295                 }
296             } finally {
297                 stateLock.writeLock().unlock();
298             }
299         }
300
301         public void startExpiringIfNotStarted() {
302             stateLock.readLock().lock();
303             try {
304                 if (running) {
305                     return;
306                 }
307             } finally {
308                 stateLock.readLock().unlock();
309             }
310
311             stateLock.writeLock().lock();
312             try {
313                 if (!running) {
314                     running = true;
315                     expirerThread.start();
316                 }
317             } finally {
318                 stateLock.writeLock().unlock();
319             }
320         }
321
322         public void stopExpiring() {
323             stateLock.writeLock().lock();
324
325             try {
326                 if (running) {
327                     running = false;
328                     expirerThread.interrupt();
329                 }
330             } finally {
331                 stateLock.writeLock().unlock();
332             }
333         }
334
335         public boolean isRunning() {
336             stateLock.readLock().lock();
337
338             try {
339                 return running;
340             } finally {
341                 stateLock.readLock().unlock();
342             }
343         }
344
345         public int getTimeToLive() {
346             stateLock.readLock().lock();
347
348             try {
349                 return (int) timeToLiveMillis / 1000;
350             } finally {
351                 stateLock.readLock().unlock();
352             }
353         }
354
355         public void setTimeToLive(long timeToLive) {
356             stateLock.writeLock().lock();
357
358             try {
359                 this.timeToLiveMillis = timeToLive * 1000;
360             } finally {
361                 stateLock.writeLock().unlock();
362             }
363         }
364
365         public int getExpirationInterval() {
366             stateLock.readLock().lock();
367
368             try {
369                 return (int) expirationIntervalMillis / 1000;
370             } finally {
371                 stateLock.readLock().unlock();
372             }
373         }
374
375         public void setExpirationInterval(long expirationInterval) {
376             stateLock.writeLock().lock();
377
378             try {
379                 this.expirationIntervalMillis = expirationInterval * 1000;
380             } finally {
381                 stateLock.writeLock().unlock();
382             }
383         }
384     }
385 }
386
Popular Tags