/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can * select the license that you prefer but you may not use this file except in * compliance with one of these Licenses. * * You can obtain a copy of the Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly at * http://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.ext.jaxrs.internal.core; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import javax.ws.rs.core.MultivaluedMap; import org.restlet.util.NamedValue; import org.restlet.util.Series; /** * An unmodifiable {@link MultivaluedMap}. * * @author Stephan Koops * * @param <K> * @param <V> */ public class UnmodifiableMultivaluedMap<K, V> implements MultivaluedMap<K, V> { /** * Creates a MultiValuedMap of unmodifiable Lists. */ private static MultivaluedMapImpl<String, String> copySeries( Series<?> series, boolean caseInsensitive) { MultivaluedMapImpl<String, String> mmap = new MultivaluedMapImpl<String, String>(); for (NamedValue<String> namedValue : series) { String key = caseInsensitive ? namedValue.getName().toLowerCase() : namedValue.getName(); mmap.add(key, namedValue.getValue()); } for (Map.Entry<String, List<String>> entry : mmap.entrySet()) { List<String> unmodifiable = Collections.unmodifiableList(entry .getValue()); mmap.put(entry.getKey(), unmodifiable); } return mmap; } /** * Returns an UnmodifiableMultivaluedMap, that contains the content of the * given {@link MultivaluedMap}. * * @param mmap * @return the created unmodifiable map */ public static UnmodifiableMultivaluedMap<String, String> get( MultivaluedMap<String, String> mmap) { return get(mmap, true); } /** * Returns an UnmodifiableMultivaluedMap, that contains the content of the * given {@link MultivaluedMap}. * * @param mmap * @param caseSensitive * @return the created unmodifiable map */ public static UnmodifiableMultivaluedMap<String, String> get( MultivaluedMap<String, String> mmap, boolean caseSensitive) { if (mmap instanceof UnmodifiableMultivaluedMap<?, ?>) { return (UnmodifiableMultivaluedMap<String, String>) mmap; } if (mmap instanceof MultivaluedMapImpl<?, ?>) { return new UnmodifiableMultivaluedMap<String, String>( (MultivaluedMapImpl<String, String>) mmap, caseSensitive); } return new UnmodifiableMultivaluedMap<String, String>( new MultivaluedMapImpl<String, String>(mmap), caseSensitive); } /** * Creates an UnmodifiableMultivaluedMap<String, String;> from the * given {@link Series}. * * @param series * @param caseSensitive * @return the created unmodifiable map */ public static UnmodifiableMultivaluedMap<String, String> getFromSeries( Series<?> series, boolean caseSensitive) { return new UnmodifiableMultivaluedMap<String, String>(copySeries( series, !caseSensitive), caseSensitive); } private final boolean caseInsensitive; private final MultivaluedMapImpl<K, V> mmap; /** * Creates a new unmodifiable {@link MultivaluedMap}. * * @param mmap * @param caseSensitive */ private UnmodifiableMultivaluedMap(MultivaluedMapImpl<K, V> mmap, boolean caseSensitive) { this.mmap = mmap; this.caseInsensitive = !caseSensitive; } public void add(K key, V value) { throw throwUnmodifiable(); } private Object caseInsensitive(Object key) { if (this.caseInsensitive && (key != null)) { key = key.toString().toLowerCase(); } return key; } public void clear() throws UnsupportedOperationException { throw throwUnmodifiable(); } public boolean containsKey(Object key) { if (this.caseInsensitive && (key != null)) { key = caseInsensitive(key.toString()); } return this.mmap.containsKey(key); } public boolean containsValue(Object value) { if (value instanceof List<?>) { return this.mmap.containsValue(value); } for (final List<V> vList : this.mmap.values()) { if (vList.contains(value)) { return true; } } return false; } public Set<java.util.Map.Entry<K, List<V>>> entrySet() { return Collections.unmodifiableSet(this.mmap.entrySet()); } @Override public boolean equals(Object anotherObect) { if (anotherObect == this) { return true; } if (!(anotherObect instanceof MultivaluedMap<?, ?>)) { return false; } return this.mmap.equals(anotherObect); } public List<V> get(Object key) { return Collections .unmodifiableList(this.mmap.get(caseInsensitive(key))); } @SuppressWarnings("unchecked") public V getFirst(K key) { if (this.caseInsensitive && (key instanceof String)) { key = (K) key.toString().toLowerCase(); } return this.mmap.getFirst(key); } /** * Returns the last element for the given key. * * @param key * @return Returns the last element for the given key. */ @SuppressWarnings("unchecked") public V getLast(K key) { if (this.caseInsensitive && (key instanceof String)) { key = (K) key.toString().toLowerCase(); } return this.mmap.getLast(key); } @Override public int hashCode() { int hashCode = this.mmap.hashCode(); if (this.caseInsensitive) { hashCode++; } return hashCode; } public boolean isEmpty() { return this.mmap.isEmpty(); } public Set<K> keySet() { return Collections.unmodifiableSet(this.mmap.keySet()); } public List<V> put(K key, List<V> value) throws UnsupportedOperationException { throw throwUnmodifiable(); } public void putAll(Map<? extends K, ? extends List<V>> t) throws UnsupportedOperationException { throw throwUnmodifiable(); } public void putSingle(K key, V value) throws UnsupportedOperationException { throw throwUnmodifiable(); } public List<V> remove(Object key) throws UnsupportedOperationException { throw throwUnmodifiable(); } public int size() { int size = 0; for (final List<V> l : this.mmap.values()) { size += l.size(); } return size; } /** * @throws UnsupportedOperationException */ private UnsupportedOperationException throwUnmodifiable() throws UnsupportedOperationException { throw new UnsupportedOperationException( "The HTTP headers are immutable"); } public Collection<List<V>> values() { return Collections.unmodifiableCollection(this.mmap.values()); } }