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