    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}