001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      https://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.collections4.collection;
019
020import java.io.Serializable;
021import java.util.Collection;
022import java.util.Iterator;
023import java.util.Objects;
024import java.util.function.Consumer;
025import java.util.function.Predicate;
026
027/**
028 * Decorates another {@link Collection} to synchronize its behavior for a multithreaded environment.
029 * <p>
030 * Iterators must be manually synchronized:
031 * </p>
032 *
033 * <pre>
034 * synchronized (coll) {
035 *     Iterator it = coll.iterator();
036 *     // do stuff with iterator
037 * }
038 * </pre>
039 * <p>
040 * This class is Serializable from Commons Collections 3.1.
041 * </p>
042 *
043 * @param <E> The type of the elements in the collection.
044 * @since 3.0
045 */
046public class SynchronizedCollection<E> implements Collection<E>, Serializable {
047
048    /** Serialization version */
049    private static final long serialVersionUID = 2412805092710877986L;
050
051    /**
052     * Creates a synchronized collection.
053     *
054     * @param <T>  The type of the elements in the collection.
055     * @param coll The collection to decorate, must not be null.
056     * @return A new synchronized collection.
057     * @throws NullPointerException if collection is null.
058     * @since 4.0
059     */
060    public static <T> SynchronizedCollection<T> synchronizedCollection(final Collection<T> coll) {
061        return new SynchronizedCollection<>(coll);
062    }
063
064    /** The collection to decorate */
065    private final Collection<E> collection;
066
067    /** The object to lock on, needed for List/SortedSet views */
068    protected final Object lock;
069
070    /**
071     * Constructs and wraps (not copies).
072     *
073     * @param collection The collection to decorate, must not be null.
074     * @throws NullPointerException if the collection is null.
075     */
076    protected SynchronizedCollection(final Collection<E> collection) {
077        this.collection = Objects.requireNonNull(collection, "collection");
078        this.lock = this;
079    }
080
081    /**
082     * Constructs and wraps (not copies).
083     *
084     * @param collection The collection to decorate, must not be null.
085     * @param lock       The lock object to use, must not be null.
086     * @throws NullPointerException if the collection or lock is null.
087     */
088    protected SynchronizedCollection(final Collection<E> collection, final Object lock) {
089        this.collection = Objects.requireNonNull(collection, "collection");
090        this.lock = Objects.requireNonNull(lock, "lock");
091    }
092
093    @Override
094    public boolean add(final E object) {
095        synchronized (lock) {
096            return decorated().add(object);
097        }
098    }
099
100    @Override
101    public boolean addAll(final Collection<? extends E> coll) {
102        synchronized (lock) {
103            return decorated().addAll(coll);
104        }
105    }
106
107    @Override
108    public void clear() {
109        synchronized (lock) {
110            decorated().clear();
111        }
112    }
113
114    @Override
115    public boolean contains(final Object object) {
116        synchronized (lock) {
117            return decorated().contains(object);
118        }
119    }
120
121    @Override
122    public boolean containsAll(final Collection<?> coll) {
123        synchronized (lock) {
124            return decorated().containsAll(coll);
125        }
126    }
127
128    /**
129     * Gets the collection being decorated.
130     *
131     * @return The decorated collection.
132     */
133    protected Collection<E> decorated() {
134        return collection;
135    }
136
137    @Override
138    public boolean equals(final Object object) {
139        synchronized (lock) {
140            if (object == this) {
141                return true;
142            }
143            return object == this || decorated().equals(object);
144        }
145    }
146
147    /**
148     * @since 4.6.0
149     */
150    @Override
151    public void forEach(final Consumer<? super E> action) {
152        synchronized (lock) {
153            decorated().forEach(action);
154        }
155    }
156
157    @Override
158    public int hashCode() {
159        synchronized (lock) {
160            return decorated().hashCode();
161        }
162    }
163
164    @Override
165    public boolean isEmpty() {
166        synchronized (lock) {
167            return decorated().isEmpty();
168        }
169    }
170
171    /**
172     * Iterators must be manually synchronized.
173     *
174     * <pre>
175     * synchronized (coll) {
176     *     Iterator it = coll.iterator();
177     *     // do stuff with iterator
178     * }
179     * </pre>
180     *
181     * @return An iterator that must be manually synchronized on the collection.
182     */
183    @Override
184    public Iterator<E> iterator() {
185        return decorated().iterator();
186    }
187
188    @Override
189    public boolean remove(final Object object) {
190        synchronized (lock) {
191            return decorated().remove(object);
192        }
193    }
194
195    @Override
196    public boolean removeAll(final Collection<?> coll) {
197        synchronized (lock) {
198            return decorated().removeAll(coll);
199        }
200    }
201
202    /**
203     * @since 4.4
204     */
205    @Override
206    public boolean removeIf(final Predicate<? super E> filter) {
207        synchronized (lock) {
208            return decorated().removeIf(filter);
209        }
210    }
211
212    @Override
213    public boolean retainAll(final Collection<?> coll) {
214        synchronized (lock) {
215            return decorated().retainAll(coll);
216        }
217    }
218
219    @Override
220    public int size() {
221        synchronized (lock) {
222            return decorated().size();
223        }
224    }
225
226    @Override
227    public Object[] toArray() {
228        synchronized (lock) {
229            return decorated().toArray();
230        }
231    }
232
233    @Override
234    public <T> T[] toArray(final T[] object) {
235        synchronized (lock) {
236            return decorated().toArray(object);
237        }
238    }
239
240    @Override
241    public String toString() {
242        synchronized (lock) {
243            return decorated().toString();
244        }
245    }
246}