1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.collections.collection;
18
19 import java.io.Serializable;
20 import java.util.Collection;
21 import java.util.Iterator;
22
23 /**
24 * Decorates another {@link Collection} to synchronize its behaviour
25 * for a multi-threaded environment.
26 * <p>
27 * Iterators must be manually synchronized:
28 * <pre>
29 * synchronized (coll) {
30 * Iterator it = coll.iterator();
31 * // do stuff with iterator
32 * }
33 * </pre>
34 * <p>
35 * This class is Serializable from Commons Collections 3.1.
36 *
37 * @param <E> the type of the elements in the collection
38 * @since 3.0
39 * @version $Id: SynchronizedCollection.java 1443602 2013-02-07 17:00:23Z tn $
40 */
41 public class SynchronizedCollection<E> implements Collection<E>, Serializable {
42
43 /** Serialization version */
44 private static final long serialVersionUID = 2412805092710877986L;
45
46 /** The collection to decorate */
47 protected final Collection<E> collection;
48 /** The object to lock on, needed for List/SortedSet views */
49 protected final Object lock;
50
51 /**
52 * Factory method to create a synchronized collection.
53 *
54 * @param <T> the type of the elements in the collection
55 * @param coll the collection to decorate, must not be null
56 * @return a new synchronized collection
57 * @throws IllegalArgumentException if collection is null
58 */
59 public static <T> SynchronizedCollection<T> synchronizedCollection(final Collection<T> coll) {
60 return new SynchronizedCollection<T>(coll);
61 }
62
63 //-----------------------------------------------------------------------
64 /**
65 * Constructor that wraps (not copies).
66 *
67 * @param collection the collection to decorate, must not be null
68 * @throws IllegalArgumentException if the collection is null
69 */
70 protected SynchronizedCollection(final Collection<E> collection) {
71 if (collection == null) {
72 throw new IllegalArgumentException("Collection must not be null");
73 }
74 this.collection = collection;
75 this.lock = this;
76 }
77
78 /**
79 * Constructor that wraps (not copies).
80 *
81 * @param collection the collection to decorate, must not be null
82 * @param lock the lock object to use, must not be null
83 * @throws IllegalArgumentException if the collection is null
84 */
85 protected SynchronizedCollection(final Collection<E> collection, final Object lock) {
86 if (collection == null) {
87 throw new IllegalArgumentException("Collection must not be null");
88 }
89 this.collection = collection;
90 this.lock = lock;
91 }
92
93 /**
94 * Gets the collection being decorated.
95 *
96 * @return the decorated collection
97 */
98 protected Collection<E> decorated() {
99 return collection;
100 }
101
102 //-----------------------------------------------------------------------
103
104 public boolean add(final E object) {
105 synchronized (lock) {
106 return decorated().add(object);
107 }
108 }
109
110 public boolean addAll(final Collection<? extends E> coll) {
111 synchronized (lock) {
112 return decorated().addAll(coll);
113 }
114 }
115
116 public void clear() {
117 synchronized (lock) {
118 decorated().clear();
119 }
120 }
121
122 public boolean contains(final Object object) {
123 synchronized (lock) {
124 return decorated().contains(object);
125 }
126 }
127
128 public boolean containsAll(final Collection<?> coll) {
129 synchronized (lock) {
130 return decorated().containsAll(coll);
131 }
132 }
133
134 public boolean isEmpty() {
135 synchronized (lock) {
136 return decorated().isEmpty();
137 }
138 }
139
140 /**
141 * Iterators must be manually synchronized.
142 * <pre>
143 * synchronized (coll) {
144 * Iterator it = coll.iterator();
145 * // do stuff with iterator
146 * }
147 *
148 * @return an iterator that must be manually synchronized on the collection
149 */
150 public Iterator<E> iterator() {
151 return decorated().iterator();
152 }
153
154 public Object[] toArray() {
155 synchronized (lock) {
156 return decorated().toArray();
157 }
158 }
159
160 public <T> T[] toArray(final T[] object) {
161 synchronized (lock) {
162 return decorated().toArray(object);
163 }
164 }
165
166 public boolean remove(final Object object) {
167 synchronized (lock) {
168 return decorated().remove(object);
169 }
170 }
171
172 public boolean removeAll(final Collection<?> coll) {
173 synchronized (lock) {
174 return decorated().removeAll(coll);
175 }
176 }
177
178 public boolean retainAll(final Collection<?> coll) {
179 synchronized (lock) {
180 return decorated().retainAll(coll);
181 }
182 }
183
184 public int size() {
185 synchronized (lock) {
186 return decorated().size();
187 }
188 }
189
190 @Override
191 public boolean equals(final Object object) {
192 synchronized (lock) {
193 if (object == this) {
194 return true;
195 }
196 return object == this || decorated().equals(object);
197 }
198 }
199
200 @Override
201 public int hashCode() {
202 synchronized (lock) {
203 return decorated().hashCode();
204 }
205 }
206
207 @Override
208 public String toString() {
209 synchronized (lock) {
210 return decorated().toString();
211 }
212 }
213
214 }