1 /* 2 * $Id: CaseInsensitiveHashMap.java 20321 2010-11-24 15:21:24Z dfeist $ 3 * -------------------------------------------------------------------------------------- 4 * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com 5 * 6 * The software in this package is published under the terms of the CPAL v1.0 7 * license, a copy of which has been included with this distribution in the 8 * LICENSE.txt file. 9 */ 10 package org.mule.util; 11 12 import java.io.IOException; 13 import java.io.ObjectInputStream; 14 import java.io.ObjectOutputStream; 15 import java.io.Serializable; 16 import java.util.Map; 17 18 import org.apache.commons.collections.map.AbstractHashedMap; 19 20 /** 21 * A case-insensitive <code>Map</code>. 22 * <p/> 23 * As entries are added to the map, keys hash values are lowercase hash codes of the key. the 24 * Real key case is preserved. 25 * <p/> 26 * <p/> 27 * The <code>keySet()</code> method returns all keys in their original case 28 * <p/> 29 * <strong>Note that CaseInsensitiveMap is not synchronized and is not thread-safe.</strong> 30 * If you wish to use this map from multiple threads concurrently, you must use 31 * appropriate synchronization. The simplest approach is to wrap this map 32 * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw 33 * exceptions when accessed by concurrent threads without synchronization. 34 * 35 * @since 3.0.0 36 */ 37 public class CaseInsensitiveHashMap extends AbstractHashedMap implements Serializable 38 { 39 /** 40 * Serialisation version 41 */ 42 private static final long serialVersionUID = -7074633917369299456L; 43 44 /** 45 * Constructs a new empty map with default size and load factor. 46 */ 47 public CaseInsensitiveHashMap() 48 { 49 super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD); 50 } 51 52 53 /** 54 * Constructs a new, empty map with the specified initial capacity. 55 * 56 * @param initialCapacity the initial capacity 57 * @throws IllegalArgumentException if the initial capacity is less than one 58 */ 59 public CaseInsensitiveHashMap(int initialCapacity) throws IllegalArgumentException 60 { 61 super(initialCapacity); 62 } 63 64 /** 65 * Constructs a new, empty map with the specified initial capacity and 66 * load factor. 67 * 68 * @param initialCapacity the initial capacity 69 * @param loadFactor the load factor 70 * @throws IllegalArgumentException if the initial capacity is less than one 71 * @throws IllegalArgumentException if the load factor is less than zero 72 */ 73 public CaseInsensitiveHashMap(int initialCapacity, float loadFactor) throws IllegalArgumentException 74 { 75 super(initialCapacity, loadFactor); 76 } 77 78 /** 79 * Constructor copying elements from another map. 80 * <p/> 81 * Keys will be converted to lower case strings, which may cause 82 * some entries to be removed (if string representation of keys differ 83 * only by character case). 84 * 85 * @param map the map to copy 86 * @throws NullPointerException if the map is null 87 */ 88 public CaseInsensitiveHashMap(Map map) 89 { 90 super(map); 91 } 92 93 /** 94 * Creates a hash value from the lower case value of the key. The same function will be used when querying 95 * a value in the map also 96 * 97 * @param key the key value to hash 98 * @return a hash value for the lower case key 99 */ 100 @Override 101 protected int hash(Object key) 102 { 103 return super.hash(key.toString().toLowerCase()); 104 } 105 106 /** 107 * Overloads the default behaviour to compare the keys without case sensitivity 108 * 109 * @param key1 the first key 110 * @param key2 the key to compare against 111 * @return true is the keys match 112 */ 113 @Override 114 protected boolean isEqualKey(Object key1, Object key2) 115 { 116 if (key1 instanceof String && key2 instanceof String) 117 { 118 return (((String) key1).equalsIgnoreCase((String) key2)); 119 } 120 else 121 { 122 return super.isEqualKey(key1, key2); 123 } 124 } 125 126 //----------------------------------------------------------------------- 127 128 /** 129 * Clones the map without cloning the keys or values. 130 * 131 * @return a shallow clone 132 */ 133 @Override 134 public Object clone() 135 { 136 return super.clone(); 137 } 138 139 /** 140 * Write the map out using a custom routine. 141 */ 142 private void writeObject(ObjectOutputStream out) throws IOException 143 { 144 out.defaultWriteObject(); 145 doWriteObject(out); 146 } 147 148 /** 149 * Read the map in using a custom routine. 150 */ 151 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException 152 { 153 in.defaultReadObject(); 154 doReadObject(in); 155 } 156 }