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.set;
018
019import java.io.IOException;
020import java.io.ObjectInputStream;
021import java.io.ObjectOutputStream;
022import java.util.Collection;
023import java.util.Iterator;
024import java.util.NavigableSet;
025import java.util.SortedSet;
026import java.util.function.Predicate;
027
028import org.apache.commons.collections4.Unmodifiable;
029import org.apache.commons.collections4.iterators.UnmodifiableIterator;
030
031/**
032 * Decorates another {@code NavigableSet} to ensure it can't be altered.
033 * <p>
034 * Attempts to modify it will result in an UnsupportedOperationException.
035 * </p>
036 *
037 * @param <E> The type of the elements in this set
038 * @since 4.1
039 */
040public final class UnmodifiableNavigableSet<E>
041        extends AbstractNavigableSetDecorator<E>
042        implements Unmodifiable {
043
044    /** Serialization version */
045    private static final long serialVersionUID = 20150528L;
046
047    /**
048     * Factory method to create an unmodifiable set.
049     *
050     * @param <E> The element type
051     * @param set  The set to decorate, must not be null
052     * @return A new unmodifiable {@link NavigableSet}
053     * @throws NullPointerException if set is null
054     */
055    public static <E> NavigableSet<E> unmodifiableNavigableSet(final NavigableSet<E> set) {
056        if (set instanceof Unmodifiable) {
057            return set;
058        }
059        return new UnmodifiableNavigableSet<>(set);
060    }
061
062    /**
063     * Constructor that wraps (not copies).
064     *
065     * @param set  The set to decorate, must not be null
066     * @throws NullPointerException if set is null
067     */
068    private UnmodifiableNavigableSet(final NavigableSet<E> set) {
069        super(set);
070    }
071
072    /**
073     * Always throws {@link UnsupportedOperationException}.
074     *
075     * @param object Ignored.
076     * @throws UnsupportedOperationException Always thrown.
077     */
078    @Override
079    public boolean add(final E object) {
080        throw new UnsupportedOperationException();
081    }
082
083    /**
084     * Always throws {@link UnsupportedOperationException}.
085     *
086     * @param coll Ignored.
087     * @throws UnsupportedOperationException Always thrown.
088     */
089    @Override
090    public boolean addAll(final Collection<? extends E> coll) {
091        throw new UnsupportedOperationException();
092    }
093
094    /**
095     * Always throws {@link UnsupportedOperationException}.
096     *
097     * @throws UnsupportedOperationException Always thrown.
098     */
099    @Override
100    public void clear() {
101        throw new UnsupportedOperationException();
102    }
103
104    @Override
105    public Iterator<E> descendingIterator() {
106        return UnmodifiableIterator.unmodifiableIterator(decorated().descendingIterator());
107    }
108
109    // NavigableSet
110    @Override
111    public NavigableSet<E> descendingSet() {
112        return unmodifiableNavigableSet(decorated().descendingSet());
113    }
114
115    @Override
116    public SortedSet<E> headSet(final E toElement) {
117        return UnmodifiableSortedSet.unmodifiableSortedSet(decorated().headSet(toElement));
118    }
119
120    @Override
121    public NavigableSet<E> headSet(final E toElement, final boolean inclusive) {
122        return unmodifiableNavigableSet(decorated().headSet(toElement, inclusive));
123    }
124
125    @Override
126    public Iterator<E> iterator() {
127        return UnmodifiableIterator.unmodifiableIterator(decorated().iterator());
128    }
129
130    /**
131     * Always throws {@link UnsupportedOperationException}.
132     *
133     * @throws UnsupportedOperationException Always thrown.
134     * @since 4.5.0-M1
135     */
136    @Override
137    public E pollFirst() {
138        throw new UnsupportedOperationException();
139    }
140
141    /**
142     * Always throws {@link UnsupportedOperationException}.
143     *
144     * @throws UnsupportedOperationException Always thrown.
145     * @since 4.5.0-M1
146     */
147    @Override
148    public E pollLast() {
149        throw new UnsupportedOperationException();
150    }
151
152    /**
153     * Deserializes the collection in using a custom routine.
154     *
155     * @param in  The input stream
156     * @throws IOException Thrown if an error occurs while reading from the stream
157     * @throws ClassNotFoundException if an object read from the stream cannot be loaded
158     */
159    @SuppressWarnings("unchecked") // (1) should only fail if input stream is incorrect
160    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
161        in.defaultReadObject();
162        setCollection((Collection<E>) in.readObject()); // (1)
163    }
164
165    /**
166     * Always throws {@link UnsupportedOperationException}.
167     *
168     * @param object Ignored.
169     * @throws UnsupportedOperationException Always thrown.
170     */
171    @Override
172    public boolean remove(final Object object) {
173        throw new UnsupportedOperationException();
174    }
175
176    /**
177     * Always throws {@link UnsupportedOperationException}.
178     *
179     * @param coll Ignored.
180     * @throws UnsupportedOperationException Always thrown.
181     */
182    @Override
183    public boolean removeAll(final Collection<?> coll) {
184        throw new UnsupportedOperationException();
185    }
186
187    /**
188     * Always throws {@link UnsupportedOperationException}.
189     *
190     * @param filter Ignored.
191     * @throws UnsupportedOperationException Always thrown.
192     * @since 4.4
193     */
194    @Override
195    public boolean removeIf(final Predicate<? super E> filter) {
196        throw new UnsupportedOperationException();
197    }
198
199    /**
200     * Always throws {@link UnsupportedOperationException}.
201     *
202     * @param coll Ignored.
203     * @throws UnsupportedOperationException Always thrown.
204     */
205    @Override
206    public boolean retainAll(final Collection<?> coll) {
207        throw new UnsupportedOperationException();
208    }
209
210    @Override
211    public NavigableSet<E> subSet(final E fromElement, final boolean fromInclusive, final E toElement,
212            final boolean toInclusive) {
213        return unmodifiableNavigableSet(decorated().subSet(fromElement, fromInclusive, toElement, toInclusive));
214    }
215
216    // SortedSet
217    @Override
218    public SortedSet<E> subSet(final E fromElement, final E toElement) {
219        return UnmodifiableSortedSet.unmodifiableSortedSet(decorated().subSet(fromElement, toElement));
220    }
221
222    @Override
223    public SortedSet<E> tailSet(final E fromElement) {
224        return UnmodifiableSortedSet.unmodifiableSortedSet(decorated().tailSet(fromElement));
225    }
226
227    @Override
228    public NavigableSet<E> tailSet(final E fromElement, final boolean inclusive) {
229        return unmodifiableNavigableSet(decorated().tailSet(fromElement, inclusive));
230    }
231
232    /**
233     * Serializes this object to an ObjectOutputStream.
234     *
235     * @param out The target ObjectOutputStream.
236     * @throws IOException thrown when an I/O errors occur writing to the target stream.
237     */
238    private void writeObject(final ObjectOutputStream out) throws IOException {
239        out.defaultWriteObject();
240        out.writeObject(decorated());
241    }
242
243}