1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package edu.internet2.middleware.shibboleth.common.util;
18
19 import java.util.Iterator;
20 import java.util.Map;
21 import java.util.concurrent.ConcurrentHashMap;
22
23 import org.opensaml.util.storage.StorageService;
24 import org.springframework.context.ApplicationContext;
25 import org.springframework.context.ApplicationContextAware;
26 import org.springframework.context.ApplicationEvent;
27
28
29
30
31
32
33
34
35
36
37
38
39 public class EventingMapBasedStorageService<KeyType, ValueType> implements StorageService<KeyType, ValueType>,
40 ApplicationContextAware {
41
42
43 private ApplicationContext appCtx;
44
45
46 private Map<String, Map<KeyType, ValueType>> store;
47
48
49 public EventingMapBasedStorageService() {
50 store = new ConcurrentHashMap<String, Map<KeyType, ValueType>>();
51 }
52
53
54 public boolean contains(String partition, Object key) {
55 if (partition == null || key == null) {
56 return false;
57 }
58
59 if (store.containsKey(partition)) {
60 return store.get(partition).containsKey(key);
61 }
62
63 return false;
64 }
65
66
67 public ValueType get(String partition, Object key) {
68 if (partition == null || key == null) {
69 return null;
70 }
71
72 if (store.containsKey(partition)) {
73 return store.get(partition).get(key);
74 }
75
76 return null;
77 }
78
79
80 public Iterator<KeyType> getKeys(String partition) {
81 return this.new PartitionEntryIterator(partition);
82 }
83
84
85 public Iterator<String> getPartitions() {
86 return this.new PartitionIterator();
87 }
88
89
90 public ValueType put(String partition, KeyType key, ValueType value) {
91 if (partition == null || key == null) {
92 return null;
93 }
94
95 Map<KeyType, ValueType> partitionMap;
96 synchronized (store) {
97 partitionMap = store.get(partition);
98 if (partitionMap == null) {
99 partitionMap = new ConcurrentHashMap<KeyType, ValueType>();
100 store.put(partition, partitionMap);
101 }
102 }
103
104 ValueType replacedEntry = partitionMap.put(key, value);
105 appCtx.publishEvent(this.new AddEntryEvent(this, partition, key, value));
106 return replacedEntry;
107 }
108
109
110 public ValueType remove(String partition, KeyType key) {
111 if (partition == null || key == null) {
112 return null;
113 }
114
115 if (store.containsKey(partition)) {
116 ValueType removedEntry = store.get(partition).remove(key);
117 appCtx.publishEvent(this.new RemoveEntryEvent(this, partition, key, removedEntry));
118 return removedEntry;
119 }
120
121 return null;
122 }
123
124
125 public void setApplicationContext(ApplicationContext ctx) {
126 ApplicationContext rootContext = ctx;
127 while (rootContext.getParent() != null) {
128 rootContext = rootContext.getParent();
129 }
130 appCtx = rootContext;
131 }
132
133
134 public class AddEntryEvent extends ApplicationEvent {
135
136
137 private static final long serialVersionUID = -1939512157260059492L;
138
139
140 private StorageService<KeyType, ValueType> storageService;
141
142
143 private String partition;
144
145
146 private KeyType key;
147
148
149 private ValueType value;
150
151
152
153
154
155
156
157
158
159 public AddEntryEvent(StorageService<KeyType, ValueType> storageService, String partition, KeyType key,
160 ValueType value) {
161 super(storageService);
162 this.storageService = storageService;
163 this.partition = partition;
164 this.key = key;
165 this.value = value;
166 }
167
168
169
170
171
172
173 public StorageService<KeyType, ValueType> getStorageService() {
174 return storageService;
175 }
176
177
178
179
180
181
182 public String getPartition() {
183 return partition;
184 }
185
186
187
188
189
190
191 public KeyType getKey() {
192 return key;
193 }
194
195
196
197
198
199
200 public ValueType getValue() {
201 return value;
202 }
203 }
204
205
206 public class RemoveEntryEvent extends ApplicationEvent {
207
208
209 private static final long serialVersionUID = 7414605158323325366L;
210
211
212 private StorageService<KeyType, ValueType> storageService;
213
214
215 private String partition;
216
217
218 private KeyType key;
219
220
221 private ValueType value;
222
223
224
225
226
227
228
229
230
231 public RemoveEntryEvent(StorageService<KeyType, ValueType> storageService, String partition, KeyType key,
232 ValueType value) {
233 super(storageService);
234 this.storageService = storageService;
235 this.partition = partition;
236 this.key = key;
237 this.value = value;
238 }
239
240
241
242
243
244
245 public StorageService<KeyType, ValueType> getStorageService() {
246 return storageService;
247 }
248
249
250
251
252
253
254 public String getPartition() {
255 return partition;
256 }
257
258
259
260
261
262
263 public KeyType getKey() {
264 return key;
265 }
266
267
268
269
270
271
272 public ValueType getValue() {
273 return value;
274 }
275 }
276
277
278 public class PartitionIterator implements Iterator<String> {
279
280
281 private Iterator<String> partitionItr;
282
283
284 private String currentParition;
285
286
287 public PartitionIterator() {
288 partitionItr = store.keySet().iterator();
289 }
290
291
292 public boolean hasNext() {
293 return partitionItr.hasNext();
294 }
295
296
297 public String next() {
298 currentParition = partitionItr.next();
299 return currentParition;
300 }
301
302
303 public void remove() {
304 Iterator<KeyType> partitionEntries = getKeys(currentParition);
305 while (partitionEntries.hasNext()) {
306 partitionEntries.next();
307 partitionEntries.remove();
308 }
309 store.remove(currentParition);
310 }
311 }
312
313
314 public class PartitionEntryIterator implements Iterator<KeyType> {
315
316
317 private String partition;
318
319
320 private Iterator<KeyType> keysItr;
321
322
323 private KeyType currentKey;
324
325
326
327
328
329
330 public PartitionEntryIterator(String partition) {
331 this.partition = partition;
332 keysItr = store.get(partition).keySet().iterator();
333 }
334
335
336 public boolean hasNext() {
337 return keysItr.hasNext();
338 }
339
340
341 public KeyType next() {
342 currentKey = keysItr.next();
343 return currentKey;
344 }
345
346
347 public void remove() {
348 EventingMapBasedStorageService.this.remove(partition, currentKey);
349 }
350 }
351 }