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}