001: /*
002: * Copyright 2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.collections.map;
017:
018: import java.io.IOException;
019: import java.io.ObjectInputStream;
020: import java.io.ObjectOutputStream;
021: import java.io.Serializable;
022: import java.util.Map;
023:
024: /**
025: * A case-insensitive <code>Map</code>.
026: * <p>
027: * As entries are added to the map, keys are converted to all lowercase. A new
028: * key is compared to existing keys by comparing <code>newKey.toString().toLower()</code>
029: * to the lowercase values in the current <code>KeySet.</code>
030: * <p>
031: * Null keys are supported.
032: * <p>
033: * The <code>keySet()</code> method returns all lowercase keys, or nulls.
034: * <p>
035: * Example:
036: * <pre><code>
037: * Map map = new CaseInsensitiveMap();
038: * map.put("One", "One");
039: * map.put("Two", "Two");
040: * map.put(null, "Three");
041: * map.put("one", "Four");
042: * </code></pre>
043: * creates a <code>CaseInsensitiveMap</code> with three entries.<br>
044: * <code>map.get(null)</code> returns <code>"Three"</code> and <code>map.get("ONE")</code>
045: * returns <code>"Four".</code> The <code>Set</code> returned by <code>keySet()</code>
046: * equals <code>{"one", "two", null}.</code>
047: * <p>
048: * <strong>Note that CaseInsensitiveMap is not synchronized and is not thread-safe.</strong>
049: * If you wish to use this map from multiple threads concurrently, you must use
050: * appropriate synchronization. The simplest approach is to wrap this map
051: * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw
052: * exceptions when accessed by concurrent threads without synchronization.
053: *
054: * @since Commons Collections 3.0
055: * @version $Revision: 348007 $ $Date: 2005-11-21 22:52:57 +0000 (Mon, 21 Nov 2005) $
056: *
057: * @author Commons-Collections team
058: */
059: public class CaseInsensitiveMap extends AbstractHashedMap implements
060: Serializable, Cloneable {
061:
062: /** Serialisation version */
063: private static final long serialVersionUID = -7074655917369299456L;
064:
065: /**
066: * Constructs a new empty map with default size and load factor.
067: */
068: public CaseInsensitiveMap() {
069: super (DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD);
070: }
071:
072: /**
073: * Constructs a new, empty map with the specified initial capacity.
074: *
075: * @param initialCapacity the initial capacity
076: * @throws IllegalArgumentException if the initial capacity is less than one
077: */
078: public CaseInsensitiveMap(int initialCapacity) {
079: super (initialCapacity);
080: }
081:
082: /**
083: * Constructs a new, empty map with the specified initial capacity and
084: * load factor.
085: *
086: * @param initialCapacity the initial capacity
087: * @param loadFactor the load factor
088: * @throws IllegalArgumentException if the initial capacity is less than one
089: * @throws IllegalArgumentException if the load factor is less than zero
090: */
091: public CaseInsensitiveMap(int initialCapacity, float loadFactor) {
092: super (initialCapacity, loadFactor);
093: }
094:
095: /**
096: * Constructor copying elements from another map.
097: * <p>
098: * Keys will be converted to lower case strings, which may cause
099: * some entries to be removed (if string representation of keys differ
100: * only by character case).
101: *
102: * @param map the map to copy
103: * @throws NullPointerException if the map is null
104: */
105: public CaseInsensitiveMap(Map map) {
106: super (map);
107: }
108:
109: //-----------------------------------------------------------------------
110: /**
111: * Overrides convertKey() from {@link AbstractHashedMap} to convert keys to
112: * lower case.
113: * <p>
114: * Returns null if key is null.
115: *
116: * @param key the key convert
117: * @return the converted key
118: */
119: protected Object convertKey(Object key) {
120: if (key != null) {
121: return key.toString().toLowerCase();
122: } else {
123: return AbstractHashedMap.NULL;
124: }
125: }
126:
127: //-----------------------------------------------------------------------
128: /**
129: * Clones the map without cloning the keys or values.
130: *
131: * @return a shallow clone
132: */
133: public Object clone() {
134: return super .clone();
135: }
136:
137: /**
138: * Write the map out using a custom routine.
139: */
140: private void writeObject(ObjectOutputStream out) throws IOException {
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,
149: ClassNotFoundException {
150: in.defaultReadObject();
151: doReadObject(in);
152: }
153:
154: }
|