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}