    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.lang.reflect.Array;
    020import java.util.Collection;
    021import java.util.Iterator;
    022import java.util.Map;
    023import java.util.Set;
    024
    025import org.apache.commons.collections4.Unmodifiable;
    026import org.apache.commons.collections4.iterators.AbstractIteratorDecorator;
    027import org.apache.commons.collections4.keyvalue.AbstractMapEntryDecorator;
    028import org.apache.commons.collections4.set.AbstractSetDecorator;
    029
    030/**
    031 * Decorates a map entry <code>Set</code> to ensure it can't be altered.
    032 * <p>
    033 * Attempts to modify it will result in an UnsupportedOperationException.
    034 *
    035 * @param <K> the type of the keys in the map
    036 * @param <V> the type of the values in the map
    037 *
    038 * @since 3.0
    039 */
    040public final class UnmodifiableEntrySet<K, V>
    041        extends AbstractSetDecorator<Map.Entry<K, V>> implements Unmodifiable {
    042
    043    /** Serialization version */
    044    private static final long serialVersionUID = 1678353579659253473L;
    045
    046    /**
    047     * Factory method to create an unmodifiable set of Map Entry objects.
    048     *
    049     * @param <K>  the key type
    050     * @param <V>  the value type
    051     * @param set  the set to decorate, must not be null
    052     * @return a new unmodifiable entry set
    053     * @throws NullPointerException if set is null
    054     * @since 4.0
    055     */
    056    public static <K, V> Set<Map.Entry<K, V>> unmodifiableEntrySet(final Set<Map.Entry<K, V>> set) {
    057        if (set instanceof Unmodifiable) {
    058            return set;
    059        }
    060        return new UnmodifiableEntrySet<>(set);
    061    }
    062
    063    //-----------------------------------------------------------------------
    064    /**
    065     * Constructor that wraps (not copies).
    066     *
    067     * @param set  the set to decorate, must not be null
    068     * @throws NullPointerException if set is null
    069     */
    070    private UnmodifiableEntrySet(final Set<Map.Entry<K, V>> set) {
    071        super(set);
    072    }
    073
    074    //-----------------------------------------------------------------------
    075    @Override
    076    public boolean add(final Map.Entry<K, V> object) {
    077        throw new UnsupportedOperationException();
    078    }
    079
    080    @Override
    081    public boolean addAll(final Collection<? extends Map.Entry<K, V>> coll) {
    082        throw new UnsupportedOperationException();
    083    }
    084
    085    @Override
    086    public void clear() {
    087        throw new UnsupportedOperationException();
    088    }
    089
    090    @Override
    091    public boolean remove(final Object object) {
    092        throw new UnsupportedOperationException();
    093    }
    094
    095    @Override
    096    public boolean removeAll(final Collection<?> coll) {
    097        throw new UnsupportedOperationException();
    098    }
    099
    100    @Override
    101    public boolean retainAll(final Collection<?> coll) {
    102        throw new UnsupportedOperationException();
    103    }
    104
    105    //-----------------------------------------------------------------------
    106    @Override
    107    public Iterator<Map.Entry<K, V>> iterator() {
    108        return new UnmodifiableEntrySetIterator(decorated().iterator());
    109    }
    110
    111    @Override
    112    @SuppressWarnings("unchecked")
    113    public Object[] toArray() {
    114        final Object[] array = decorated().toArray();
    115        for (int i = 0; i < array.length; i++) {
    116            array[i] = new UnmodifiableEntry((Map.Entry<K, V>) array[i]);
    117        }
    118        return array;
    119    }
    120
    121    @Override
    122    @SuppressWarnings("unchecked")
    123    public <T> T[] toArray(final T[] array) {
    124        Object[] result = array;
    125        if (array.length > 0) {
    126            // we must create a new array to handle multi-threaded situations
    127            // where another thread could access data before we decorate it
    128            result = (Object[]) Array.newInstance(array.getClass().getComponentType(), 0);
    129        }
    130        result = decorated().toArray(result);
    131        for (int i = 0; i < result.length; i++) {
    132            result[i] = new UnmodifiableEntry((Map.Entry<K, V>) result[i]);
    133        }
    134
    135        // check to see if result should be returned straight
    136        if (result.length > array.length) {
    137            return (T[]) result;
    138        }
    139
    140        // copy back into input array to fulfill the method contract
    141        System.arraycopy(result, 0, array, 0, result.length);
    142        if (array.length > result.length) {
    143            array[result.length] = null;
    144        }
    145        return array;
    146    }
    147
    148    //-----------------------------------------------------------------------
    149    /**
    150     * Implementation of an entry set iterator.
    151     */
    152    private class UnmodifiableEntrySetIterator extends AbstractIteratorDecorator<Map.Entry<K, V>> {
    153
    154        protected UnmodifiableEntrySetIterator(final Iterator<Map.Entry<K, V>> iterator) {
    155            super(iterator);
    156        }
    157
    158        @Override
    159        public Map.Entry<K, V> next() {
    160            return new UnmodifiableEntry(getIterator().next());
    161        }
    162
    163        @Override
    164        public void remove() {
    165            throw new UnsupportedOperationException();
    166        }
    167    }
    168
    169    //-----------------------------------------------------------------------
    170    /**
    171     * Implementation of a map entry that is unmodifiable.
    172     */
    173    private class UnmodifiableEntry extends AbstractMapEntryDecorator<K, V> {
    174
    175        protected UnmodifiableEntry(final Map.Entry<K, V> entry) {
    176            super(entry);
    177        }
    178
    179        @Override
    180        public V setValue(final V obj) {
    181            throw new UnsupportedOperationException();
    182        }
    183    }
    184
    185}