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.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     * Factory method to create 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     * Factory method to create 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     *
078     * @param <E> the type of the elements in the collection
079     * @param collection  the {@code BoundedCollection} to decorate, must not be null
080     * @return a new unmodifiable bounded collection
081     * @throws NullPointerException if coll is null
082     * @throws IllegalArgumentException if coll is not a {@code BoundedCollection}
083     * @since 4.0
084     */
085    @SuppressWarnings("unchecked")
086    public static <E> BoundedCollection<E> unmodifiableBoundedCollection(Collection<? extends E> collection) {
087        Objects.requireNonNull(collection, "collection");
088
089        // handle decorators
090        for (int i = 0; i < 1000; i++) {  // counter to prevent infinite looping
091            if (collection instanceof BoundedCollection) {
092                break;  // normal loop exit
093            }
094            if (collection instanceof AbstractCollectionDecorator) {
095                collection = ((AbstractCollectionDecorator<E>) collection).decorated();
096            } else if (collection instanceof SynchronizedCollection) {
097                collection = ((SynchronizedCollection<E>) collection).decorated();
098            }
099        }
100
101        if (!(collection instanceof BoundedCollection)) {
102            throw new IllegalArgumentException("Collection is not a bounded collection.");
103        }
104        return new UnmodifiableBoundedCollection<>((BoundedCollection<E>) collection);
105    }
106
107    /**
108     * Constructor that wraps (not copies).
109     *
110     * @param coll  the collection to decorate, must not be null
111     * @throws NullPointerException if coll is null
112     */
113    @SuppressWarnings("unchecked") // safe to upcast
114    private UnmodifiableBoundedCollection(final BoundedCollection<? extends E> coll) {
115        super((BoundedCollection<E>) coll);
116    }
117
118    @Override
119    public boolean add(final E object) {
120        throw new UnsupportedOperationException();
121    }
122
123    @Override
124    public boolean addAll(final Collection<? extends E> coll) {
125        throw new UnsupportedOperationException();
126    }
127
128    @Override
129    public void clear() {
130        throw new UnsupportedOperationException();
131    }
132
133    @Override
134    protected BoundedCollection<E> decorated() {
135        return (BoundedCollection<E>) super.decorated();
136    }
137
138    @Override
139    public boolean isFull() {
140        return decorated().isFull();
141    }
142
143    @Override
144    public Iterator<E> iterator() {
145        return UnmodifiableIterator.unmodifiableIterator(decorated().iterator());
146    }
147
148    @Override
149    public int maxSize() {
150        return decorated().maxSize();
151    }
152
153    @Override
154    public boolean remove(final Object object) {
155        throw new UnsupportedOperationException();
156    }
157
158    @Override
159    public boolean removeAll(final Collection<?> coll) {
160        throw new UnsupportedOperationException();
161    }
162
163    /**
164     * @since 4.4
165     */
166    @Override
167    public boolean removeIf(final Predicate<? super E> filter) {
168        throw new UnsupportedOperationException();
169    }
170
171    @Override
172    public boolean retainAll(final Collection<?> coll) {
173        throw new UnsupportedOperationException();
174    }
175}