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