/*
* Copyright 2012 The Solmix Project
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.gnu.org/licenses/
* or see the FSF site: http://www.fsf.org.
*/
package org.solmix.commons.collections;
import java.util.HashMap;
import java.util.Map;
/**
* A Map that converts all keys to lowercase Strings for case insensitive
* lookups. This is needed for the toMap() implementation because
* databases don't consistenly handle the casing of column names.
*
* <p>The keys are stored as they are given [BUG #DBUTILS-34], so we maintain
* an internal mapping from lowercase keys to the real keys in order to
* achieve the case insensitive lookup.
*
* <p>Note: This implementation does not allow <tt>null</tt>
* for key, whereas {@link HashMap} does, because of the code:
* <pre>
* key.toString().toLowerCase()
* </pre>
* @author solmix.f@gmail.com
* @version 110035 2011-8-28
* @param <V>
* @param <K>
*/
public class CaseInsensitiveHashMap extends HashMap<String, Object> {
/**
* The internal mapping from lowercase keys to the real keys.
*
* <p>
* Any query operation using the key
* ({@link #get(Object)}, {@link #containsKey(Object)})
* is done in three steps:
* <ul>
* <li>convert the parameter key to lower case</li>
* <li>get the actual key that corresponds to the lower case key</li>
* <li>query the map with the actual key</li>
* </ul>
* </p>
*/
private final Map<String,String> lowerCaseMap = new HashMap<String,String>();
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = -2848100435296897392L;
/** {@inheritDoc} */
@Override
public boolean containsKey(Object key) {
Object realKey = lowerCaseMap.get(key.toString().toLowerCase());
return super.containsKey(realKey);
// Possible optimisation here:
// Since the lowerCaseMap contains a mapping for all the keys,
// we could just do this:
// return lowerCaseMap.containsKey(key.toString().toLowerCase());
}
/** {@inheritDoc} */
@Override
public Object get(Object key) {
Object realKey = lowerCaseMap.get(key.toString().toLowerCase());
return super.get(realKey);
}
/** {@inheritDoc} */
@Override
public Object put(String key, Object value) {
/*
* In order to keep the map and lowerCaseMap synchronized,
* we have to remove the old mapping before putting the
* new one. Indeed, oldKey and key are not necessaliry equals.
* (That's why we call super.remove(oldKey) and not just
* super.put(key, value))
*/
Object oldKey = lowerCaseMap.put(key.toLowerCase(), key);
Object oldValue = super.remove(oldKey);
super.put(key, value);
return oldValue;
}
/** {@inheritDoc} */
@Override
public void putAll(Map<? extends String,?> m) {
for (Map.Entry<? extends String, ?> entry : m.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
this.put(key, value);
}
}
/** {@inheritDoc} */
@Override
public Object remove(Object key) {
Object realKey = lowerCaseMap.remove(key.toString().toLowerCase());
return super.remove(realKey);
}
}