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}