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