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