package org.jboss.resteasy.util;

import org.jboss.resteasy.specimpl.MultivaluedTreeMap;

import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

Author:Bill Burke
Version:$Revision: 1 $
/** * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @version $Revision: 1 $ */
@SuppressWarnings("unchecked") //public class CaseInsensitiveMap<V> implements MultivaluedMap<String, V>, Serializable public class CaseInsensitiveMap<V> extends MultivaluedTreeMap<String, V> { public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator(); private static class CaseInsensitiveComparator implements Comparator<String>, java.io.Serializable { public int compare(String s1, String s2) { if (s1 == s2) return 0; int n1 = 0; // null check is different than JDK version of this method if (s1 != null) n1 = s1.length(); int n2 = 0; if (s2 != null) n2 = s2.length(); int min = Math.min(n1, n2); for (int i = 0; i < min; i++) { char c1 = s1.charAt(i); char c2 = s2.charAt(i); if (c1 != c2) { c1 = Character.toLowerCase(c1); c2 = Character.toLowerCase(c2); if (c1 != c2) { // No overflow because of numeric promotion return c1 - c2; } } } return n1 - n2; } } public CaseInsensitiveMap() { super(CASE_INSENSITIVE_ORDER); } /* 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(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || !(o instanceof Set)) return false; Set<String> strings = (Set<String>) o; if (size() != strings.size()) return false; for (String string : strings) { if (!contains(string)) return false; } return true; } @Override 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 int hashCode = 0; private String tlc; private CaseInsensitiveKey(String key) { this.key = key; if (key != null) { tlc = key.toLowerCase(); hashCode = tlc.hashCode(); } } public final boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CaseInsensitiveKey that = (CaseInsensitiveKey) o; if (tlc == that.tlc) return true; if (tlc == null || that.tlc == null) return false; return tlc.equals(that.tlc); } public final int hashCode() { return hashCode; } public final String toString() { return key; } } private MultivaluedMap<CaseInsensitiveKey, V> map = new MultivaluedHashMap<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 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) { String key = o == null ? null : o.toString(); return map.containsKey(new CaseInsensitiveKey(key)); } public boolean containsValue(Object o) { return map.containsValue(o); } public List<V> get(Object o) { String key = o == null ? null : o.toString(); return map.get(new CaseInsensitiveKey(key)); } public List<V> put(String s, List<V> vs) { return map.put(new CaseInsensitiveKey(s), vs); } public List<V> remove(Object o) { String key = o == null ? null : o.toString(); return map.remove(new CaseInsensitiveKey(key)); } private List<V> getMapList(CaseInsensitiveKey key) { List<V> list = map.get(key); if (list == null) map.put(key, list = new ArrayList<V>()); return list; } 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) { getMapList(entry.getKey()).addAll(entry.getValue()); } } else { for (Map.Entry<String, List<V>> entry : (Set<Entry<String, List<V>>>) otherMap.entrySet()) { getMapList(new CaseInsensitiveKey(entry.getKey())).addAll(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()); } @Override public void addAll(String key, V... newValues) { for (V value : newValues) { add(key, value); } } @Override public void addAll(String key, List<V> valueList) { for (V value : valueList) { add(key, value); } } @Override public void addFirst(String key, V value) { List<V> list = get(key); if (list == null) { add(key, value); return; } else { list.add(0, value); } } @Override public boolean equalsIgnoreValueOrder(MultivaluedMap<String, V> omap) { if (this == omap) { return true; } if (!keySet().equals(omap.keySet())) { return false; } for (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; } */ }