    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 */
    017package org.apache.commons.collections4.collection;
    018
    019import java.util.Collection;
    020import java.util.Iterator;
    021import java.util.Objects;
    022import java.util.function.Predicate;
    023
    024import org.apache.commons.collections4.BoundedCollection;
    025import org.apache.commons.collections4.Unmodifiable;
    026import org.apache.commons.collections4.iterators.UnmodifiableIterator;
    027
    028/**
    029 * {@link UnmodifiableBoundedCollection} decorates another
    030 * {@link BoundedCollection} to ensure it can't be altered.
    031 * <p>
    032 * If a BoundedCollection is first wrapped in some other collection decorator,
    033 * such as synchronized or predicated, the BoundedCollection methods are no
    034 * longer accessible.
    035 * The factory on this class will attempt to retrieve the bounded nature by
    036 * examining the package scope variables.
    037 * </p>
    038 * <p>
    039 * This class is Serializable from Commons Collections 3.1.
    040 * </p>
    041 * <p>
    042 * Attempts to modify it will result in an UnsupportedOperationException.
    043 * </p>
    044 *
    045 * @param <E> The type of elements in this collection.
    046 * @since 3.0
    047 */
    048public final class UnmodifiableBoundedCollection<E> extends AbstractCollectionDecorator<E>
    049        implements BoundedCollection<E>, Unmodifiable {
    050
    051    /** Serialization version */
    052    private static final long serialVersionUID = -7112672385450340330L;
    053
    054    /**
    055     * Creates an unmodifiable bounded collection.
    056     *
    057     * @param <E> The type of the elements in the collection.
    058     * @param coll  The {@code BoundedCollection} to decorate, must not be null.
    059     * @return A new unmodifiable bounded collection.
    060     * @throws NullPointerException if {@code coll} is {@code null}.
    061     * @since 4.0
    062     */
    063    public static <E> BoundedCollection<E> unmodifiableBoundedCollection(final BoundedCollection<? extends E> coll) {
    064        if (coll instanceof Unmodifiable) {
    065            @SuppressWarnings("unchecked") // safe to upcast
    066            final BoundedCollection<E> tmpColl = (BoundedCollection<E>) coll;
    067            return tmpColl;
    068        }
    069        return new UnmodifiableBoundedCollection<>(coll);
    070    }
    071
    072    /**
    073     * Creates an unmodifiable bounded collection.
    074     * <p>
    075     * This method is capable of drilling down through up to 1000 other decorators
    076     * to find a suitable BoundedCollection.
    077     * </p>
    078     *
    079     * @param <E> The type of the elements in the collection.
    080     * @param collection  The {@code BoundedCollection} to decorate, must not be null.
    081     * @return A new unmodifiable bounded collection.
    082     * @throws NullPointerException if coll is null.
    083     * @throws IllegalArgumentException if coll is not a {@code BoundedCollection}.
    084     * @since 4.0
    085     */
    086    @SuppressWarnings("unchecked")
    087    public static <E> BoundedCollection<E> unmodifiableBoundedCollection(Collection<? extends E> collection) {
    088        Objects.requireNonNull(collection, "collection");
    089
    090        // handle decorators
    091        for (int i = 0; i < 1000; i++) {  // counter to prevent infinite looping
    092            if (collection instanceof BoundedCollection) {
    093                break;  // normal loop exit
    094            }
    095            if (collection instanceof AbstractCollectionDecorator) {
    096                collection = ((AbstractCollectionDecorator<E>) collection).decorated();
    097            } else if (collection instanceof SynchronizedCollection) {
    098                collection = ((SynchronizedCollection<E>) collection).decorated();
    099            }
    100        }
    101
    102        if (!(collection instanceof BoundedCollection)) {
    103            throw new IllegalArgumentException("Collection is not a bounded collection.");
    104        }
    105        return new UnmodifiableBoundedCollection<>((BoundedCollection<E>) collection);
    106    }
    107
    108    /**
    109     * Constructs and wraps (not copies).
    110     *
    111     * @param coll  The collection to decorate, must not be null.
    112     * @throws NullPointerException if coll is null.
    113     */
    114    @SuppressWarnings("unchecked") // safe to upcast
    115    private UnmodifiableBoundedCollection(final BoundedCollection<? extends E> coll) {
    116        super((BoundedCollection<E>) coll);
    117    }
    118
    119    /**
    120     * Always throws {@link UnsupportedOperationException}.
    121     *
    122     * @param object Ignored.
    123     * @throws UnsupportedOperationException Always thrown.
    124     */
    125    @Override
    126    public boolean add(final E object) {
    127        throw new UnsupportedOperationException();
    128    }
    129
    130    /**
    131     * Always throws {@link UnsupportedOperationException}.
    132     *
    133     * @param coll Ignored.
    134     * @throws UnsupportedOperationException Always thrown.
    135     */
    136    @Override
    137    public boolean addAll(final Collection<? extends E> coll) {
    138        throw new UnsupportedOperationException();
    139    }
    140
    141    /**
    142     * Always throws {@link UnsupportedOperationException}.
    143     *
    144     * @throws UnsupportedOperationException Always thrown.
    145     */
    146    @Override
    147    public void clear() {
    148        throw new UnsupportedOperationException();
    149    }
    150
    151    @Override
    152    protected BoundedCollection<E> decorated() {
    153        return (BoundedCollection<E>) super.decorated();
    154    }
    155
    156    @Override
    157    public boolean isFull() {
    158        return decorated().isFull();
    159    }
    160
    161    @Override
    162    public Iterator<E> iterator() {
    163        return UnmodifiableIterator.unmodifiableIterator(decorated().iterator());
    164    }
    165
    166    @Override
    167    public int maxSize() {
    168        return decorated().maxSize();
    169    }
    170
    171    /**
    172     * Always throws {@link UnsupportedOperationException}.
    173     *
    174     * @param object Ignored.
    175     * @throws UnsupportedOperationException Always thrown.
    176     */
    177    @Override
    178    public boolean remove(final Object object) {
    179        throw new UnsupportedOperationException();
    180    }
    181
    182    /**
    183     * Always throws {@link UnsupportedOperationException}.
    184     *
    185     * @param coll Ignored.
    186     * @throws UnsupportedOperationException Always thrown.
    187     */
    188    @Override
    189    public boolean removeAll(final Collection<?> coll) {
    190        throw new UnsupportedOperationException();
    191    }
    192
    193    /**
    194     * Always throws {@link UnsupportedOperationException}.
    195     *
    196     * @param filter Ignored.
    197     * @throws UnsupportedOperationException Always thrown.
    198     * @since 4.4
    199     */
    200    @Override
    201    public boolean removeIf(final Predicate<? super E> filter) {
    202        throw new UnsupportedOperationException();
    203    }
    204
    205    /**
    206     * Always throws {@link UnsupportedOperationException}.
    207     *
    208     * @param Ignored.
    209     * @throws UnsupportedOperationException Always thrown.
    210     */
    211    @Override
    212    public boolean retainAll(final Collection<?> coll) {
    213        throw new UnsupportedOperationException();
    214    }
    215}