1 package com.atlassian.plugin.util.concurrent;
2
3 import static com.atlassian.plugin.util.Assertions.notNull;
4
5 import java.io.Serializable;
6 import java.util.Collection;
7 import java.util.Iterator;
8 import java.util.Map;
9 import java.util.Set;
10
11 abstract class AbstractCopyOnWriteMap<K, V, M extends Map<K, V>> implements Map<K, V>, Serializable
12 {
13 private static final long serialVersionUID = 4508989182041753878L;
14
15 private volatile M delegate;
16 private final transient EntrySet entrySet = new EntrySet();
17 private final transient KeySet keySet = new KeySet();
18 private final transient Values values = new Values();
19
20
21
22
23
24
25
26
27 protected <N extends Map<? extends K, ? extends V>> AbstractCopyOnWriteMap(final N map)
28 {
29 this.delegate = notNull("delegate", copy(notNull("map", map)));
30 }
31
32 abstract <N extends Map<? extends K, ? extends V>> M copy(N map);
33
34
35
36
37
38 public synchronized final void clear()
39 {
40 final M map = copy();
41 map.clear();
42 set(map);
43 }
44
45 public synchronized final V remove(final Object key)
46 {
47
48 if (!delegate.containsKey(key))
49 {
50 return null;
51 }
52 final M map = copy();
53 final V result = map.remove(key);
54 set(map);
55 return result;
56 }
57
58 public synchronized final V put(final K key, final V value)
59 {
60 final M map = copy();
61 final V result = map.put(key, value);
62 set(map);
63 return result;
64 }
65
66 public synchronized final void putAll(final Map<? extends K, ? extends V> t)
67 {
68 final M map = copy();
69 map.putAll(t);
70 set(map);
71 }
72
73 protected synchronized void removeAll(final Collection<K> keys)
74 {
75 final M map = copy();
76 for (final K k : keys)
77 {
78 map.remove(k);
79 }
80 set(map);
81 }
82
83 protected synchronized M copy()
84 {
85 return copy(delegate);
86 }
87
88 protected synchronized void set(final M map)
89 {
90 delegate = map;
91 }
92
93
94
95
96
97 public final Set<Map.Entry<K, V>> entrySet()
98 {
99 return entrySet;
100 }
101
102 public final Set<K> keySet()
103 {
104 return keySet;
105 }
106
107 public final Collection<V> values()
108 {
109 return values;
110 }
111
112
113
114
115
116 public final boolean containsKey(final Object key)
117 {
118 return delegate.containsKey(key);
119 }
120
121 public final boolean containsValue(final Object value)
122 {
123 return delegate.containsValue(value);
124 }
125
126 public final V get(final Object key)
127 {
128 return delegate.get(key);
129 }
130
131 public final boolean isEmpty()
132 {
133 return delegate.isEmpty();
134 }
135
136 public final int size()
137 {
138 return delegate.size();
139 }
140
141 @Override
142 public final boolean equals(final Object o)
143 {
144 return delegate.equals(o);
145 }
146
147 @Override
148 public final int hashCode()
149 {
150 return delegate.hashCode();
151 }
152
153 protected final M getDelegate()
154 {
155 return delegate;
156 }
157
158 @Override
159 public String toString()
160 {
161 return delegate.toString();
162 }
163
164
165
166
167
168
169
170
171
172 private class KeySet extends CollectionView<K> implements Set<K>
173 {
174
175 @Override
176 Collection<K> getDelegate()
177 {
178 return delegate.keySet();
179 }
180
181
182
183
184
185 public void clear()
186 {
187 synchronized (AbstractCopyOnWriteMap.this)
188 {
189 final M map = copy();
190 map.keySet().clear();
191 set(map);
192 }
193 }
194
195 public boolean remove(final Object o)
196 {
197 return AbstractCopyOnWriteMap.this.remove(o) != null;
198 }
199
200 public boolean removeAll(final Collection<?> c)
201 {
202 synchronized (AbstractCopyOnWriteMap.this)
203 {
204 final M map = copy();
205 final boolean result = map.keySet().removeAll(c);
206 set(map);
207 return result;
208 }
209 }
210
211 public boolean retainAll(final Collection<?> c)
212 {
213 synchronized (AbstractCopyOnWriteMap.this)
214 {
215 final M map = copy();
216 final boolean result = map.keySet().retainAll(c);
217 set(map);
218 return result;
219 }
220 }
221 }
222
223 private final class Values extends CollectionView<V> implements Collection<V>
224 {
225
226 @Override
227 Collection<V> getDelegate()
228 {
229 return delegate.values();
230 }
231
232 public void clear()
233 {
234 synchronized (AbstractCopyOnWriteMap.this)
235 {
236 final M map = copy();
237 map.values().clear();
238 set(map);
239 }
240 }
241
242 public boolean remove(final Object o)
243 {
244 synchronized (AbstractCopyOnWriteMap.this)
245 {
246 if (!contains(o))
247 {
248 return false;
249 }
250 final M map = copy();
251 final boolean result = map.values().remove(o);
252 set(map);
253 return result;
254 }
255 }
256
257 public boolean removeAll(final Collection<?> c)
258 {
259 synchronized (AbstractCopyOnWriteMap.this)
260 {
261 final M map = copy();
262 final boolean result = map.values().removeAll(c);
263 set(map);
264 return result;
265 }
266 }
267
268 public boolean retainAll(final Collection<?> c)
269 {
270 synchronized (AbstractCopyOnWriteMap.this)
271 {
272 final M map = copy();
273 final boolean result = map.values().retainAll(c);
274 set(map);
275 return result;
276 }
277 }
278 }
279
280 private class EntrySet extends CollectionView<Entry<K, V>> implements Set<Map.Entry<K, V>>
281 {
282
283 @Override
284 Collection<java.util.Map.Entry<K, V>> getDelegate()
285 {
286 return delegate.entrySet();
287 }
288
289 public void clear()
290 {
291 synchronized (AbstractCopyOnWriteMap.this)
292 {
293 final M map = copy();
294 map.entrySet().clear();
295 set(map);
296 }
297 }
298
299 public boolean remove(final Object o)
300 {
301 synchronized (AbstractCopyOnWriteMap.this)
302 {
303 if (!contains(o))
304 {
305 return false;
306 }
307 final M map = copy();
308 final boolean result = map.entrySet().remove(o);
309 set(map);
310 return result;
311 }
312 }
313
314 public boolean removeAll(final Collection<?> c)
315 {
316 synchronized (AbstractCopyOnWriteMap.this)
317 {
318 final M map = copy();
319 final boolean result = map.entrySet().removeAll(c);
320 set(map);
321 return result;
322 }
323 }
324
325 public boolean retainAll(final Collection<?> c)
326 {
327 synchronized (AbstractCopyOnWriteMap.this)
328 {
329 final M map = copy();
330 final boolean result = map.entrySet().retainAll(c);
331 set(map);
332 return result;
333 }
334 }
335 }
336
337 private static class UnmodifiableIterator<T> implements Iterator<T>
338 {
339 private final Iterator<T> delegate;
340
341 public UnmodifiableIterator(final Iterator<T> delegate)
342 {
343 this.delegate = delegate;
344 }
345
346 public boolean hasNext()
347 {
348 return delegate.hasNext();
349 }
350
351 public T next()
352 {
353 return delegate.next();
354 }
355
356 public void remove()
357 {
358 throw new UnsupportedOperationException();
359 }
360 }
361
362 protected static abstract class CollectionView<E> implements Collection<E>
363 {
364
365 abstract Collection<E> getDelegate();
366
367
368
369
370
371 public final boolean contains(final Object o)
372 {
373 return getDelegate().contains(o);
374 }
375
376 public final boolean containsAll(final Collection<?> c)
377 {
378 return getDelegate().containsAll(c);
379 }
380
381 public final Iterator<E> iterator()
382 {
383 return new UnmodifiableIterator<E>(getDelegate().iterator());
384 }
385
386 public final boolean isEmpty()
387 {
388 return getDelegate().isEmpty();
389 }
390
391 public final int size()
392 {
393 return getDelegate().size();
394 }
395
396 public final Object[] toArray()
397 {
398 return getDelegate().toArray();
399 }
400
401 public final <T> T[] toArray(final T[] a)
402 {
403 return getDelegate().toArray(a);
404 }
405
406 @Override
407 public int hashCode()
408 {
409 return getDelegate().hashCode();
410 }
411
412 @Override
413 public boolean equals(final Object obj)
414 {
415 return getDelegate().equals(obj);
416 }
417
418
419
420
421
422 public final boolean add(final E o)
423 {
424 throw new UnsupportedOperationException();
425 }
426
427 public final boolean addAll(final Collection<? extends E> c)
428 {
429 throw new UnsupportedOperationException();
430 }
431 }
432 }