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