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