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 *      http://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 */
017package org.apache.commons.collections4.collection;
018
019import java.io.Serializable;
020import java.util.Collection;
021import java.util.Iterator;
022import java.util.Objects;
023import java.util.function.Predicate;
024
025/**
026 * Decorates another {@link Collection} to synchronize its behavior
027 * for a multithreaded environment.
028 * <p>
029 * Iterators must be manually synchronized:
030 * </p>
031 * <pre>
032 * synchronized (coll) {
033 *   Iterator it = coll.iterator();
034 *   // do stuff with iterator
035 * }
036 * </pre>
037 * <p>
038 * This class is Serializable from Commons Collections 3.1.
039 * </p>
040 *
041 * @param <E> the type of the elements in the collection
042 * @since 3.0
043 */
044public class SynchronizedCollection<E> implements Collection<E>, Serializable {
045
046    /** Serialization version */
047    private static final long serialVersionUID = 2412805092710877986L;
048
049    /**
050     * Factory method to create a synchronized collection.
051     *
052     * @param <T> the type of the elements in the collection
053     * @param coll  the collection to decorate, must not be null
054     * @return a new synchronized collection
055     * @throws NullPointerException if collection is null
056     * @since 4.0
057     */
058    public static <T> SynchronizedCollection<T> synchronizedCollection(final Collection<T> coll) {
059        return new SynchronizedCollection<>(coll);
060    }
061    /** The collection to decorate */
062    private final Collection<E> collection;
063
064    /** The object to lock on, needed for List/SortedSet views */
065    protected final Object lock;
066
067    /**
068     * Constructor that wraps (not copies).
069     *
070     * @param collection  the collection to decorate, must not be null
071     * @throws NullPointerException if the collection is null
072     */
073    protected SynchronizedCollection(final Collection<E> collection) {
074        this.collection = Objects.requireNonNull(collection, "collection");
075        this.lock = this;
076    }
077
078    /**
079     * Constructor that wraps (not copies).
080     *
081     * @param collection  the collection to decorate, must not be null
082     * @param lock  the lock object to use, must not be null
083     * @throws NullPointerException if the collection or lock is null
084     */
085    protected SynchronizedCollection(final Collection<E> collection, final Object lock) {
086        this.collection = Objects.requireNonNull(collection, "collection");
087        this.lock = Objects.requireNonNull(lock, "lock");
088    }
089
090    @Override
091    public boolean add(final E object) {
092        synchronized (lock) {
093            return decorated().add(object);
094        }
095    }
096
097    @Override
098    public boolean addAll(final Collection<? extends E> coll) {
099        synchronized (lock) {
100            return decorated().addAll(coll);
101        }
102    }
103
104    @Override
105    public void clear() {
106        synchronized (lock) {
107            decorated().clear();
108        }
109    }
110
111    @Override
112    public boolean contains(final Object object) {
113        synchronized (lock) {
114            return decorated().contains(object);
115        }
116    }
117
118    @Override
119    public boolean containsAll(final Collection<?> coll) {
120        synchronized (lock) {
121            return decorated().containsAll(coll);
122        }
123    }
124
125    /**
126     * Gets the collection being decorated.
127     *
128     * @return the decorated collection
129     */
130    protected Collection<E> decorated() {
131        return collection;
132    }
133
134    @Override
135    public boolean equals(final Object object) {
136        synchronized (lock) {
137            if (object == this) {
138                return true;
139            }
140            return object == this || decorated().equals(object);
141        }
142    }
143
144    @Override
145    public int hashCode() {
146        synchronized (lock) {
147            return decorated().hashCode();
148        }
149    }
150
151    @Override
152    public boolean isEmpty() {
153        synchronized (lock) {
154            return decorated().isEmpty();
155        }
156    }
157
158    /**
159     * Iterators must be manually synchronized.
160     * <pre>
161     * synchronized (coll) {
162     *   Iterator it = coll.iterator();
163     *   // do stuff with iterator
164     * }
165     * </pre>
166     *
167     * @return an iterator that must be manually synchronized on the collection
168     */
169    @Override
170    public Iterator<E> iterator() {
171        return decorated().iterator();
172    }
173
174    @Override
175    public boolean remove(final Object object) {
176        synchronized (lock) {
177            return decorated().remove(object);
178        }
179    }
180
181    @Override
182    public boolean removeAll(final Collection<?> coll) {
183        synchronized (lock) {
184            return decorated().removeAll(coll);
185        }
186    }
187
188    /**
189     * @since 4.4
190     */
191    @Override
192    public boolean removeIf(final Predicate<? super E> filter) {
193        synchronized (lock) {
194            return decorated().removeIf(filter);
195        }
196    }
197
198    @Override
199    public boolean retainAll(final Collection<?> coll) {
200        synchronized (lock) {
201            return decorated().retainAll(coll);
202        }
203    }
204
205    @Override
206    public int size() {
207        synchronized (lock) {
208            return decorated().size();
209        }
210    }
211
212    @Override
213    public Object[] toArray() {
214        synchronized (lock) {
215            return decorated().toArray();
216        }
217    }
218
219    @Override
220    public <T> T[] toArray(final T[] object) {
221        synchronized (lock) {
222            return decorated().toArray(object);
223        }
224    }
225
226    @Override
227    public String toString() {
228        synchronized (lock) {
229            return decorated().toString();
230        }
231    }
232
233}