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