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.map;
018
019import java.io.IOException;
020import java.io.ObjectInputStream;
021import java.io.ObjectOutputStream;
022import java.io.Serializable;
023import java.util.Collection;
024import java.util.Comparator;
025import java.util.Map;
026import java.util.Set;
027import java.util.SortedMap;
028
029import org.apache.commons.collections4.Unmodifiable;
030import org.apache.commons.collections4.collection.UnmodifiableCollection;
031import org.apache.commons.collections4.set.UnmodifiableSet;
032
033/**
034 * Decorates another {@code SortedMap} to ensure it can't be altered.
035 * <p>
036 * This class is Serializable from Commons Collections 3.1.
037 * </p>
038 * <p>
039 * Attempts to modify it will result in an UnsupportedOperationException.
040 * </p>
041 *
042 * @param <K> The type of the keys in this map
043 * @param <V> The type of the values in this map
044 * @since 3.0
045 */
046public final class UnmodifiableSortedMap<K, V>
047        extends AbstractSortedMapDecorator<K, V>
048        implements Unmodifiable, Serializable {
049
050    /** Serialization version */
051    private static final long serialVersionUID = 5805344239827376360L;
052
053    /**
054     * Factory method to create an unmodifiable sorted map.
055     *
056     * @param <K>  the key type
057     * @param <V>  the value type
058     * @param map  The map to decorate, must not be null
059     * @return A new unmodifiable sorted map
060     * @throws NullPointerException if map is null
061     * @since 4.0
062     */
063    public static <K, V> SortedMap<K, V> unmodifiableSortedMap(final SortedMap<K, ? extends V> map) {
064        if (map instanceof Unmodifiable) {
065            @SuppressWarnings("unchecked") // safe to upcast
066            final SortedMap<K, V> tmpMap = (SortedMap<K, V>) map;
067            return tmpMap;
068        }
069        return new UnmodifiableSortedMap<>(map);
070    }
071
072    /**
073     * Constructor that wraps (not copies).
074     *
075     * @param map  The map to decorate, must not be null
076     * @throws NullPointerException if map is null
077     */
078    @SuppressWarnings("unchecked") // safe to upcast
079    private UnmodifiableSortedMap(final SortedMap<K, ? extends V> map) {
080        super((SortedMap<K, V>) map);
081    }
082
083    /**
084     * Always throws {@link UnsupportedOperationException}.
085     *
086     * @throws UnsupportedOperationException Always thrown.
087     */
088    @Override
089    public void clear() {
090        throw new UnsupportedOperationException();
091    }
092
093    @Override
094    public Comparator<? super K> comparator() {
095        return decorated().comparator();
096    }
097
098    @Override
099    public Set<Map.Entry<K, V>> entrySet() {
100        return UnmodifiableEntrySet.unmodifiableEntrySet(super.entrySet());
101    }
102
103    @Override
104    public K firstKey() {
105        return decorated().firstKey();
106    }
107
108    @Override
109    public SortedMap<K, V> headMap(final K toKey) {
110        return new UnmodifiableSortedMap<>(decorated().headMap(toKey));
111    }
112
113    @Override
114    public Set<K> keySet() {
115        return UnmodifiableSet.unmodifiableSet(super.keySet());
116    }
117
118    @Override
119    public K lastKey() {
120        return decorated().lastKey();
121    }
122
123    /**
124     * Always throws {@link UnsupportedOperationException}.
125     *
126     * @param key Ignored.
127     * @param value Ignored.
128     * @throws UnsupportedOperationException Always thrown.
129     */
130    @Override
131    public V put(final K key, final V value) {
132        throw new UnsupportedOperationException();
133    }
134
135    /**
136     * Always throws {@link UnsupportedOperationException}.
137     *
138     * @param mapToCopy Ignored.
139     * @throws UnsupportedOperationException Always thrown.
140     */
141    @Override
142    public void putAll(final Map<? extends K, ? extends V> mapToCopy) {
143        throw new UnsupportedOperationException();
144    }
145
146    /**
147     * Deserializes the map in using a custom routine.
148     *
149     * @param in  The input stream
150     * @throws IOException Thrown if an error occurs while reading from the stream
151     * @throws ClassNotFoundException if an object read from the stream cannot be loaded
152     * @since 3.1
153     */
154    @SuppressWarnings("unchecked")
155    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
156        in.defaultReadObject();
157        map = (Map<K, V>) in.readObject();
158    }
159
160    /**
161     * Always throws {@link UnsupportedOperationException}.
162     *
163     * @param key Ignored.
164     * @throws UnsupportedOperationException Always thrown.
165     */
166    @Override
167    public V remove(final Object key) {
168        throw new UnsupportedOperationException();
169    }
170
171    @Override
172    public SortedMap<K, V> subMap(final K fromKey, final K toKey) {
173        return new UnmodifiableSortedMap<>(decorated().subMap(fromKey, toKey));
174    }
175
176    @Override
177    public SortedMap<K, V> tailMap(final K fromKey) {
178        return new UnmodifiableSortedMap<>(decorated().tailMap(fromKey));
179    }
180
181    @Override
182    public Collection<V> values() {
183        return UnmodifiableCollection.unmodifiableCollection(super.values());
184    }
185
186    /**
187     * Serializes this object to an ObjectOutputStream.
188     *
189     * @param out The target ObjectOutputStream.
190     * @throws IOException thrown when an I/O errors occur writing to the target stream.
191     * @since 3.1
192     */
193    private void writeObject(final ObjectOutputStream out) throws IOException {
194        out.defaultWriteObject();
195        out.writeObject(map);
196    }
197
198}