View Javadoc

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 }