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