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