View Javadoc

1   /**
2    * Copyright 2008 Atlassian Pty Ltd 
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); 
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at 
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0 
9    * 
10   * Unless required by applicable law or agreed to in writing, software 
11   * distributed under the License is distributed on an "AS IS" BASIS, 
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
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       * Create a new {@link CopyOnWriteMap} with the supplied {@link Map} to
40       * initialize the values and the {@link CopyFunction} for creating our
41       * actual delegate instances.
42       * 
43       * @param map the initial map to initialize with
44       * @param factory the copy function
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      // mutable operations
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          // short circuit if key doesn't exist
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     // Collection views
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     // delegate operations
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     // inner classes
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         // mutable operations
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         // delegate operations
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         // unsupported operations
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 }