001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright 2005-2011 the ConQAT Project                                   |
004|                                                                          |
005| Licensed under the Apache License, Version 2.0 (the "License");          |
006| you may not use this file except in compliance with the License.         |
007| 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.conqat.lib.commons.collections;
018
019import java.util.Collection;
020import java.util.HashMap;
021import java.util.Map;
022import java.util.Set;
023
024/**
025 * Map implementation that supports case-insensitive String keys. Note that
026 * while the method signatures of the {@link Map} interface allows arbitrary
027 * Objects as keys, this class will throw {@link IllegalArgumentException}s when
028 * using non String keys (null keys are supported). Also note that {link
029 * {@link #keySet()}} will return lower cased keys.
030 */
031public class CaseInsensitiveMap<T> implements Map<String, T> {
032
033        /** The delegate map */
034        private final Map<String, T> delegateMap = new HashMap<>();
035
036        /** {@inheritDoc} */
037        @Override
038        public int size() {
039                return delegateMap.size();
040        }
041
042        /** {@inheritDoc} */
043        @Override
044        public boolean isEmpty() {
045                return delegateMap.isEmpty();
046        }
047
048        /** {@inheritDoc} */
049        @Override
050        public boolean containsKey(Object key) {
051                return delegateMap.containsKey(preprocessKey(key));
052        }
053
054        /** {@inheritDoc} */
055        @Override
056        public boolean containsValue(Object value) {
057                return delegateMap.containsValue(value);
058        }
059
060        /** {@inheritDoc} */
061        @Override
062        public T get(Object key) {
063                return delegateMap.get(preprocessKey(key));
064        }
065
066        /** {@inheritDoc} */
067        @Override
068        public T put(String key, T value) {
069                return delegateMap.put(preprocessKey(key), value);
070        }
071
072        /** {@inheritDoc} */
073        @Override
074        public T remove(Object key) {
075                return delegateMap.remove(preprocessKey(key));
076        }
077
078        /** {@inheritDoc} */
079        @Override
080        public void putAll(Map<? extends String, ? extends T> m) {
081                for (java.util.Map.Entry<? extends String, ? extends T> entry : m.entrySet()) {
082                        delegateMap.put(preprocessKey(entry.getKey()), entry.getValue());
083                }
084        }
085
086        /** {@inheritDoc} */
087        @Override
088        public void clear() {
089                delegateMap.clear();
090        }
091
092        /**
093         * Returns the keys of this map in <b>lower case</b>. Note that this (mutable)
094         * set does no longer possess the case-insensitivity feature.
095         */
096        @Override
097        public Set<String> keySet() {
098                return delegateMap.keySet();
099        }
100
101        /** {@inheritDoc} */
102        @Override
103        public Collection<T> values() {
104                return delegateMap.values();
105        }
106
107        /**
108         * Returns the entries of this map. The keys of the entries will we in lower
109         * case.
110         */
111        /** {@inheritDoc} */
112        @Override
113        public Set<java.util.Map.Entry<String, T>> entrySet() {
114                return delegateMap.entrySet();
115        }
116
117        /**
118         * Preprocesses a key by converting it to lower case. This can handle
119         * <code>null</code> keys.
120         */
121        private static String preprocessKey(Object key) {
122                if (key == null) {
123                        return null;
124                }
125                if (key instanceof String) {
126                        return ((String) key).toLowerCase();
127                }
128                throw new IllegalArgumentException("Only keys of type String allowed");
129        }
130
131        /** {@inheritDoc} */
132        @Override
133        public String toString() {
134                return delegateMap.toString();
135        }
136
137}