1
2
3
4
5
6
7
8
9
10 package org.mule.util.store;
11
12 import org.mule.api.store.ObjectAlreadyExistsException;
13 import org.mule.api.store.ObjectDoesNotExistException;
14 import org.mule.api.store.ObjectStoreException;
15 import org.mule.config.i18n.CoreMessages;
16
17 import java.io.Serializable;
18 import java.util.Iterator;
19 import java.util.Map;
20
21 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentSkipListMap;
22 import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
23
24
25
26
27
28
29
30
31 public class InMemoryObjectStore<T extends Serializable> extends AbstractMonitoredObjectStore<T>
32 {
33 protected ConcurrentSkipListMap
34
35 public InMemoryObjectStore()
36 {
37 this.store = new ConcurrentSkipListMap();
38 }
39
40
41
42
43 public boolean contains(Serializable key) throws ObjectStoreException
44 {
45 if (key == null)
46 {
47 throw new ObjectStoreException(CoreMessages.objectIsNull("id"));
48 }
49
50 synchronized (store)
51 {
52 return store.values().contains(new StoredObject<T>(key, null));
53 }
54 }
55
56
57
58
59 public void store(Serializable id, T value) throws ObjectStoreException
60 {
61 if (id == null)
62 {
63 throw new ObjectStoreException(CoreMessages.objectIsNull("id"));
64 }
65
66
67
68 StoredObject<T> obj = new StoredObject<T>(id, value);
69 synchronized (store)
70 {
71 if (store.values().contains(obj))
72 {
73 throw new ObjectAlreadyExistsException();
74 }
75
76 boolean written = false;
77 while (!written)
78 {
79 Long key = Long.valueOf(System.nanoTime());
80 written = (store.put(key, obj) == null);
81 }
82 }
83 }
84
85
86
87
88 @SuppressWarnings("unchecked")
89 public T retrieve(Serializable key) throws ObjectStoreException
90 {
91 synchronized (store)
92 {
93 Map.Entry<?, ?> entry = findEntry(key);
94 if (entry != null)
95 {
96 StoredObject object = (StoredObject) entry.getValue();
97 return (T)object.getItem();
98 }
99 }
100
101 throw new ObjectDoesNotExistException(CoreMessages.objectNotFound(key));
102 }
103
104 @SuppressWarnings("unchecked")
105 private Map.Entry<?, ?> findEntry(Serializable key)
106 {
107 Iterator<?> entryIterator = store.entrySet().iterator();
108 while (entryIterator.hasNext())
109 {
110 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) entryIterator.next();
111
112 StoredObject object = (StoredObject) entry.getValue();
113 if (object.getId().equals(key))
114 {
115 return entry;
116 }
117 }
118 return null;
119 }
120
121 @SuppressWarnings("unchecked")
122 public T remove(Serializable key) throws ObjectStoreException
123 {
124 synchronized (store)
125 {
126 Map.Entry<?, ?> entry = findEntry(key);
127 if (entry != null)
128 {
129 StoredObject removedObject = (StoredObject) store.remove(entry.getKey());
130 return (T)removedObject.getItem();
131 }
132 }
133
134 throw new ObjectDoesNotExistException(CoreMessages.objectNotFound(key));
135 }
136
137 @Override
138 public void expire()
139 {
140
141 int currentSize = store.size();
142
143
144 currentSize = trimToMaxSize(currentSize);
145
146
147 if ((entryTTL > 0) && (currentSize != 0))
148 {
149 final long now = System.nanoTime();
150 int expiredEntries = 0;
151 Map.Entry<?, ?> oldestEntry;
152
153 purge:
154 while ((oldestEntry = store.firstEntry()) != null)
155 {
156 Long oldestKey = (Long) oldestEntry.getKey();
157 long oldestKeyValue = oldestKey.longValue();
158
159 if (TimeUnit.NANOSECONDS.toMillis(now - oldestKeyValue) >= entryTTL)
160 {
161 store.remove(oldestKey);
162 expiredEntries++;
163 }
164 else
165 {
166 break purge;
167 }
168 }
169
170 if (logger.isDebugEnabled())
171 {
172 logger.debug("Expired " + expiredEntries + " old entries");
173 }
174 }
175 }
176
177 private int trimToMaxSize(int currentSize)
178 {
179 if (maxEntries < 0)
180 {
181 return currentSize;
182 }
183
184 int excess = (currentSize - maxEntries);
185 if (excess > 0)
186 {
187 while (currentSize > maxEntries)
188 {
189 store.pollFirstEntry();
190 currentSize--;
191 }
192
193 if (logger.isDebugEnabled())
194 {
195 logger.debug("Expired " + excess + " excess entries");
196 }
197 }
198 return currentSize;
199 }
200
201 @Override
202 public String toString()
203 {
204 return getClass().getSimpleName() + " " + store;
205 }
206
207
208
209
210 protected static class StoredObject<T>
211 {
212 private Serializable id;
213 private T item;
214
215 public StoredObject(Serializable id, T item)
216 {
217 this.id = id;
218 this.item = item;
219 }
220
221 public Serializable getId()
222 {
223 return id;
224 }
225
226 public T getItem()
227 {
228 return item;
229 }
230
231 @Override
232 @SuppressWarnings("unchecked")
233 public boolean equals(Object o)
234 {
235 if (this == o)
236 {
237 return true;
238 }
239 if (o == null || getClass() != o.getClass())
240 {
241 return false;
242 }
243
244 StoredObject that = (StoredObject) o;
245
246 if (!id.equals(that.id))
247 {
248 return false;
249 }
250
251 return true;
252 }
253
254 @Override
255 public int hashCode()
256 {
257 return id.hashCode();
258 }
259
260 @Override
261 public String toString()
262 {
263 final StringBuffer sb = new StringBuffer();
264 sb.append("StoredObject");
265 sb.append("{id='").append(id).append('\'');
266 sb.append(", item=").append(item);
267 sb.append('}');
268 return sb.toString();
269 }
270 }
271 }