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