/* * Copyright 2014 cruxframework.org. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.cruxframework.crux.core.server.rest.util; import java.io.Serializable; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.cruxframework.crux.core.server.rest.core.MultivaluedMap; import org.cruxframework.crux.core.server.rest.core.MultivaluedMapImpl; /** * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @version $Revision: 1 $ */ @SuppressWarnings("unchecked") public class CaseInsensitiveMap<V> implements MultivaluedMap<String, V>, Serializable { private static class KeySetWrapper implements Set<String> { private Set<CaseInsensitiveKey> keys; public KeySetWrapper(Set<CaseInsensitiveKey> keys) { this.keys = keys; } public int size() { return keys.size(); } public boolean isEmpty() { return keys.isEmpty(); } public boolean contains(Object o) { return keys.contains(new CaseInsensitiveKey((String) o)); } public Iterator<String> iterator() { return new Iterator<String>() { private Iterator<CaseInsensitiveKey> it = keys.iterator(); public boolean hasNext() { return it.hasNext(); } public String next() { return it.next().key; } public void remove() { it.remove(); } }; } public Object[] toArray() { return toArray(new String[keys.size()]); } public <T> T[] toArray(T[] ks) { int i = 0; for (CaseInsensitiveKey key : keys) { ks[i++] = (T) key.key; } return ks; } public boolean add(String key) { return keys.add(new CaseInsensitiveKey(key)); } public boolean remove(Object o) { return keys.remove(new CaseInsensitiveKey(o.toString())); } public boolean containsAll(Collection<?> objects) { HashSet<CaseInsensitiveKey> objs = new HashSet<CaseInsensitiveKey>(); for (Object o : objects) { objs.add(new CaseInsensitiveKey(o.toString())); } return keys.containsAll(objs); } public boolean addAll(Collection<? extends String> objects) { HashSet<CaseInsensitiveKey> objs = new HashSet<CaseInsensitiveKey>(); for (Object o : objects) { objs.add(new CaseInsensitiveKey(o.toString())); } return keys.addAll(objs); } public boolean retainAll(Collection<?> objects) { HashSet<CaseInsensitiveKey> objs = new HashSet<CaseInsensitiveKey>(); for (Object o : objects) { objs.add(new CaseInsensitiveKey(o.toString())); } return keys.retainAll(objects); } public boolean removeAll(Collection<?> objects) { HashSet<CaseInsensitiveKey> objs = new HashSet<CaseInsensitiveKey>(); for (Object o : objects) { objs.add(new CaseInsensitiveKey(o.toString())); } return keys.removeAll(objects); } public void clear() { keys.clear(); } public boolean equals(Object o) { return keys.equals(o); } public int hashCode() { return keys.hashCode(); } } private static class EntrySetWrapper<V> implements Set<Entry<String, V>> { private Set<Entry<CaseInsensitiveKey, V>> entrySet; private EntrySetWrapper(Set<Entry<CaseInsensitiveKey, V>> entrySet) { this.entrySet = entrySet; } public int size() { return entrySet.size(); } public boolean isEmpty() { return entrySet.isEmpty(); } public boolean contains(Object o) { if (!(o instanceof Entry)) return false; return entrySet.contains(new EntryWrapper<V>((Entry<String, V>) o)); } public Iterator<Entry<String, V>> iterator() { return new Iterator<Entry<String, V>>() { Iterator<Entry<CaseInsensitiveKey, V>> it = entrySet.iterator(); public boolean hasNext() { return it.hasNext(); } public Entry<String, V> next() { return new EntryDelegate<V>(it.next()); } public void remove() { it.remove(); } }; } public Object[] toArray() { Entry<String, V>[] array = new Entry[entrySet.size()]; return toArray(array); } public <T> T[] toArray(T[] ts) { Entry<String, V>[] array = (Entry<String, V>[]) ts; int i = 0; for (Entry<CaseInsensitiveKey, V> entry : entrySet) { array[i++] = new EntryDelegate(entry); } return (T[]) array; } public boolean add(Entry<String, V> stringVEntry) { entrySet.add(new EntryWrapper<V>(stringVEntry)); return false; } public boolean remove(Object o) { return entrySet.remove(new EntryWrapper<V>((Entry<String, V>) o)); } public boolean containsAll(Collection<?> objects) { Collection<Entry<String, V>> list = (Collection<Entry<String, V>>) objects; HashSet<Entry<CaseInsensitiveKey, V>> set = new HashSet<Entry<CaseInsensitiveKey, V>>(); for (Entry<String, V> entry : list) { set.add(new EntryWrapper<V>(entry)); } return entrySet.containsAll(set); } public boolean addAll(Collection<? extends Entry<String, V>> entries) { HashSet<Entry<CaseInsensitiveKey, V>> set = new HashSet<Entry<CaseInsensitiveKey, V>>(); for (Entry<String, V> entry : entries) { set.add(new EntryWrapper<V>(entry)); } return entrySet.addAll(set); } public boolean retainAll(Collection<?> objects) { Collection<Entry<String, V>> list = (Collection<Entry<String, V>>) objects; HashSet<Entry<CaseInsensitiveKey, V>> set = new HashSet<Entry<CaseInsensitiveKey, V>>(); for (Entry<String, V> entry : list) { set.add(new EntryWrapper<V>(entry)); } return entrySet.retainAll(set); } public boolean removeAll(Collection<?> objects) { Collection<Entry<String, V>> list = (Collection<Entry<String, V>>) objects; HashSet<Entry<CaseInsensitiveKey, V>> set = new HashSet<Entry<CaseInsensitiveKey, V>>(); for (Entry<String, V> entry : list) { set.add(new EntryWrapper<V>(entry)); } return entrySet.removeAll(set); } public void clear() { entrySet.clear(); } private class EntryWrapper<T> implements Entry<CaseInsensitiveKey, T> { private CaseInsensitiveKey key; private T value; public EntryWrapper(Entry<String, T> entry) { key = new CaseInsensitiveKey(entry.getKey()); value = entry.getValue(); } public CaseInsensitiveKey getKey() { return key; } public T getValue() { return value; } public T setValue(T v) { T tmp = value; value = v; return tmp; } } private class EntryDelegate<T> implements Entry<String, T> { private Entry<CaseInsensitiveKey, T> entry; private EntryDelegate(Entry<CaseInsensitiveKey, T> entry) { this.entry = entry; } public final String getKey() { return entry.getKey().key; } public final T getValue() { return entry.getValue(); } public final T setValue(T v) { return entry.setValue(v); } } } private static class CaseInsensitiveKey implements Serializable { private static final long serialVersionUID = 6249456709345532524L; private String key; private String tlc; private int hashCode = -1; private CaseInsensitiveKey(String key) { this.key = key; tlc = key.toLowerCase(); } public final boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CaseInsensitiveKey that = (CaseInsensitiveKey) o; return tlc.equals(that.tlc); } public final int hashCode() { if (hashCode == -1) hashCode = tlc.hashCode(); return hashCode; } public final String toString() { return key; } } private MultivaluedMapImpl<CaseInsensitiveKey, V> map = new MultivaluedMapImpl<CaseInsensitiveKey, V>(); public void putSingle(String key, V value) { map.putSingle(new CaseInsensitiveKey(key), value); } public void add(String key, V value) { map.add(new CaseInsensitiveKey(key), value); } public void addMultiple(String key, Collection<V> value) { map.addMultiple(new CaseInsensitiveKey(key), value); } public V getFirst(String key) { return map.getFirst(new CaseInsensitiveKey(key)); } public final int size() { return map.size(); } public boolean isEmpty() { return map.isEmpty(); } public boolean containsKey(Object o) { return map.containsKey(new CaseInsensitiveKey(o.toString())); } public boolean containsValue(Object o) { return map.containsValue(o); } public List<V> get(Object o) { return map.get(new CaseInsensitiveKey(o.toString())); } public List<V> put(String s, List<V> vs) { return map.put(new CaseInsensitiveKey(s), vs); } public List<V> remove(Object o) { return map.remove(new CaseInsensitiveKey(o.toString())); } public final void putAll(Map otherMap) { if (otherMap instanceof CaseInsensitiveMap) { CaseInsensitiveMap otherCaseInsensitiveMap = ((CaseInsensitiveMap) otherMap); Set<Map.Entry<CaseInsensitiveKey, List<V>>> es = otherCaseInsensitiveMap.map.entrySet(); for (Entry<CaseInsensitiveKey, List<V>> entry : es) { map.addMultiple(entry.getKey(), entry.getValue()); } } else { for (Map.Entry<String, List<V>> entry : (Set<Entry<String, List<V>>>) otherMap.entrySet()) { this.map.addMultiple(new CaseInsensitiveKey(entry.getKey()), entry.getValue()); } } } public void clear() { map.clear(); } public Set<String> keySet() { return new KeySetWrapper(map.keySet()); } public Collection<List<V>> values() { return map.values(); } public Set<Entry<String, List<V>>> entrySet() { return new EntrySetWrapper<List<V>>(map.entrySet()); } public void addAll(String key, V... newValues) { for (V value : newValues) { add(key, value); } } public void addAll(String key, List<V> valueList) { for (V value : valueList) { add(key, value); } } public void addFirst(String key, V value) { List<V> list = get(key); if (list == null) { add(key, value); return; } else { list.add(0, value); } } public boolean equalsIgnoreValueOrder(MultivaluedMap<String, V> omap) { if (this == omap) { return true; } if (!keySet().equals(omap.keySet())) { return false; } for (Map.Entry<String, List<V>> e : entrySet()) { List<V> olist = omap.get(e.getKey()); if (e.getValue().size() != olist.size()) { return false; } for (V v : e.getValue()) { if (!olist.contains(v)) { return false; } } } return true; } }