View Javadoc

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       * Create a new {@link CopyOnWriteMap} with the supplied {@link Map} to initialize the values
22       * and the {@link CopyFunction} for creating our actual delegate instances.
23       * 
24       * @param map the initial map to initialize with
25       * @param factory the copy function
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      // mutable operations
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          // short circuit if key doesn't exist
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      // Collection views
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     // delegate operations
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     // inner interfaces
166     //
167 
168     //
169     // inner classes
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         // mutable operations
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         // delegate operations
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         // unsupported operations
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 }