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 * @version $Id: SynchronizedCollection.html 972421 2015-11-14 20:00:04Z tn $
040 */
041public class SynchronizedCollection<E> implements Collection<E>, Serializable {
042
043    /** Serialization version */
044    private static final long serialVersionUID = 2412805092710877986L;
045
046    /** The collection to decorate */
047    private final Collection<E> collection;
048    /** The object to lock on, needed for List/SortedSet views */
049    protected final Object lock;
050
051    /**
052     * Factory method to create 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 IllegalArgumentException if collection is null
058     * @since 4.0
059     */
060    public static <T> SynchronizedCollection<T> synchronizedCollection(final Collection<T> coll) {
061        return new SynchronizedCollection<T>(coll);
062    }
063
064    //-----------------------------------------------------------------------
065    /**
066     * Constructor that wraps (not copies).
067     *
068     * @param collection  the collection to decorate, must not be null
069     * @throws IllegalArgumentException if the collection is null
070     */
071    protected SynchronizedCollection(final Collection<E> collection) {
072        if (collection == null) {
073            throw new IllegalArgumentException("Collection must not be null");
074        }
075        this.collection = collection;
076        this.lock = this;
077    }
078
079    /**
080     * Constructor that wraps (not copies).
081     *
082     * @param collection  the collection to decorate, must not be null
083     * @param lock  the lock object to use, must not be null
084     * @throws IllegalArgumentException if the collection is null
085     */
086    protected SynchronizedCollection(final Collection<E> collection, final Object lock) {
087        if (collection == null) {
088            throw new IllegalArgumentException("Collection must not be null");
089        }
090        this.collection = collection;
091        this.lock = lock;
092    }
093
094    /**
095     * Gets the collection being decorated.
096     *
097     * @return the decorated collection
098     */
099    protected Collection<E> decorated() {
100        return collection;
101    }
102
103    //-----------------------------------------------------------------------
104
105    public boolean add(final E object) {
106        synchronized (lock) {
107            return decorated().add(object);
108        }
109    }
110
111    public boolean addAll(final Collection<? extends E> coll) {
112        synchronized (lock) {
113            return decorated().addAll(coll);
114        }
115    }
116
117    public void clear() {
118        synchronized (lock) {
119            decorated().clear();
120        }
121    }
122
123    public boolean contains(final Object object) {
124        synchronized (lock) {
125            return decorated().contains(object);
126        }
127    }
128
129    public boolean containsAll(final Collection<?> coll) {
130        synchronized (lock) {
131            return decorated().containsAll(coll);
132        }
133    }
134
135    public boolean isEmpty() {
136        synchronized (lock) {
137            return decorated().isEmpty();
138        }
139    }
140
141    /**
142     * Iterators must be manually synchronized.
143     * <pre>
144     * synchronized (coll) {
145     *   Iterator it = coll.iterator();
146     *   // do stuff with iterator
147     * }
148     * </pre>
149     *
150     * @return an iterator that must be manually synchronized on the collection
151     */
152    public Iterator<E> iterator() {
153        return decorated().iterator();
154    }
155
156    public Object[] toArray() {
157        synchronized (lock) {
158            return decorated().toArray();
159        }
160    }
161
162    public <T> T[] toArray(final T[] object) {
163        synchronized (lock) {
164            return decorated().toArray(object);
165        }
166    }
167
168    public boolean remove(final Object object) {
169        synchronized (lock) {
170            return decorated().remove(object);
171        }
172    }
173
174    public boolean removeAll(final Collection<?> coll) {
175        synchronized (lock) {
176            return decorated().removeAll(coll);
177        }
178    }
179
180    public boolean retainAll(final Collection<?> coll) {
181        synchronized (lock) {
182            return decorated().retainAll(coll);
183        }
184    }
185
186    public int size() {
187        synchronized (lock) {
188            return decorated().size();
189        }
190    }
191
192    @Override
193    public boolean equals(final Object object) {
194        synchronized (lock) {
195            if (object == this) {
196                return true;
197            }
198            return object == this || decorated().equals(object);
199        }
200    }
201
202    @Override
203    public int hashCode() {
204        synchronized (lock) {
205            return decorated().hashCode();
206        }
207    }
208
209    @Override
210    public String toString() {
211        synchronized (lock) {
212            return decorated().toString();
213        }
214    }
215
216}