View Javadoc

1   /***
2    * 
3    * Copyright 2005 LogicBlaze, Inc. http://www.logicblaze.com
4    * 
5    * Licensed under the Apache License, Version 2.0 (the "License"); 
6    * you may not use this file except in compliance with the License. 
7    * You may obtain a copy of the License at 
8    * 
9    * http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, 
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License. 
16   * 
17   **/
18  package org.logicblaze.lingo.util;
19  
20  import edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService;
21  import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.Map;
29  import java.util.Set;
30  import java.util.SortedSet;
31  import java.util.TreeSet;
32  
33  /***
34   * 
35   * @version $Revision$
36   */
37  public class DefaultTimeoutMap implements TimeoutMap, Runnable {
38  
39      private static final Log log = LogFactory.getLog(DefaultTimeoutMap.class);
40  
41      private Map map = new HashMap();
42      private SortedSet index = new TreeSet();
43      private ScheduledExecutorService executor;
44      private long purgePollTime;
45  
46      public DefaultTimeoutMap() {
47          this(null, 1000L);
48      }
49  
50      public DefaultTimeoutMap(ScheduledExecutorService executor, long requestMapPollTimeMillis) {
51          this.executor = executor;
52          this.purgePollTime = purgePollTime;
53          schedulePoll();
54      }
55  
56      public Object get(Object key) {
57          TimeoutMapEntry entry = null;
58          synchronized (map) {
59              entry = (TimeoutMapEntry) map.get(key);
60              if (entry == null) {
61                  return null;
62              }
63              index.remove(entry);
64              updateExpireTime(entry);
65              index.add(entry);
66          }
67          return entry.getValue();
68      }
69  
70      public void put(Object key, Object value, long timeoutMillis) {
71          TimeoutMapEntry entry = new TimeoutMapEntry(key, value, timeoutMillis);
72          synchronized (map) {
73              Object oldValue = map.put(key, entry);
74              if (oldValue != null) {
75                  index.remove(oldValue);
76              }
77              updateExpireTime(entry);
78              index.add(entry);
79          }
80      }
81  
82      public void remove(Object id) {
83          synchronized (map) {
84              TimeoutMapEntry entry = (TimeoutMapEntry) map.remove(id);
85              if (entry != null) {
86                  index.remove(entry);
87              }
88          }
89      }
90  
91      /***
92       * Returns a copy of the keys in the map
93       */
94      public Object[] getKeys() {
95          Object[] keys = null;
96          synchronized (map) {
97              Set keySet = map.keySet();
98              keys = new String[keySet.size()];
99              keySet.toArray(keys);
100         }
101         return keys;
102     }
103 
104     /***
105      * The timer task which purges old requests and schedules another poll
106      */
107     public void run() {
108         purge();
109         schedulePoll();
110     }
111 
112     /***
113      * Purges any old entries from the map
114      */
115     public void purge() {
116         long now = currentTime();
117         synchronized (map) {
118             for (Iterator iter = index.iterator(); iter.hasNext();) {
119                 TimeoutMapEntry entry = (TimeoutMapEntry) iter.next();
120                 if (entry == null) {
121                     break;
122                 }
123                 if (entry.getExpireTime() < now) {
124                     if (isValidForEviction(entry)) {
125                         if (log.isDebugEnabled()) {
126                             log.debug("Evicting inactive request for correlationID: " + entry);
127                         }
128                         System.out.println("Evicting inactive request for correlationID: " + entry);
129                         map.remove(entry.getKey());
130                         iter.remove();
131                     }
132                 }
133                 else {
134                     break;
135                 }
136             }
137         }
138     }
139 
140     // Properties
141     // -------------------------------------------------------------------------
142     public long getPurgePollTime() {
143         return purgePollTime;
144     }
145 
146     /***
147      * Sets the next purge poll time in milliseconds
148      */
149     public void setPurgePollTime(long purgePollTime) {
150         this.purgePollTime = purgePollTime;
151     }
152 
153     public ScheduledExecutorService getExecutor() {
154         return executor;
155     }
156 
157     /***
158      * Sets the executor used to schedule purge events of inactive requests
159      */
160     public void setExecutor(ScheduledExecutorService executor) {
161         this.executor = executor;
162     }
163 
164     // Implementation methods
165     // -------------------------------------------------------------------------
166 
167     /***
168      * lets schedule each time to allow folks to change the time at runtime
169      */
170     protected void schedulePoll() {
171         if (executor != null) {
172             executor.schedule(this, purgePollTime, TimeUnit.MILLISECONDS);
173         }
174     }
175 
176     /***
177      * A hook to allow derivations to avoid evicting the current entry
178      * 
179      * @param entry
180      * @return
181      */
182     protected boolean isValidForEviction(TimeoutMapEntry entry) {
183         return true;
184     }
185 
186     protected void updateExpireTime(TimeoutMapEntry entry) {
187         long now = currentTime();
188         entry.setExpireTime(entry.getTimeout() + now);
189     }
190 
191     protected long currentTime() {
192         return System.currentTimeMillis();
193     }
194 }