001: /**********************************************************************************
002: *
003: * Copyright (c) 2003, 2004 The Regents of the University of Michigan, Trustees of Indiana University,
004: * Board of Trustees of the Leland Stanford, Jr., University, and The MIT Corporation
005: *
006: * Licensed under the Educational Community License Version 1.0 (the "License");
007: * By obtaining, using and/or copying this Original Work, you agree that you have read,
008: * understand, and will comply with the terms and conditions of the Educational Community License.
009: * You may obtain a copy of the License at:
010: *
011: * http://cvs.sakaiproject.org/licenses/license_1_0.html
012: *
013: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
014: * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
015: * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
016: * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
017: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
018: *
019: **********************************************************************************/package edu.indiana.lib.twinpeaks.util;
020:
021: import java.io.*;
022: import java.util.*;
023:
024: /**
025: * CaseBlindHashMap - a HashMap extension, using <code>String</code>s as
026: * key values.
027: * <p>
028: * Internally, keys are case insensitive: <code>ABC</code> = <code>abc</code>.
029: * <p>
030: * Two methods have been added to facilitate working with Sets of key strings.
031: * See <code>stringKeySet()</code> and <code>stringKeyIterator()</code>.
032: */
033: public class CaseBlindHashMap extends HashMap {
034:
035: private static org.apache.commons.logging.Log _log = LogUtils
036: .getLog(CaseBlindHashMap.class);
037:
038: /**
039: * Constructors
040: */
041: public CaseBlindHashMap() {
042: super ();
043: }
044:
045: public CaseBlindHashMap(CaseBlindHashMap map) {
046: super (map);
047: }
048:
049: public CaseBlindHashMap(int initCap) {
050: super (initCap);
051: }
052:
053: public CaseBlindHashMap(int initCap, float loadFactor) {
054: super (initCap, loadFactor);
055: }
056:
057: /*
058: * Extensions
059: */
060:
061: /**
062: * Get the set of keys contained in this map. Keys values are returned as
063: * simple <code>String</code>s (not the <code>CaseBlindString</code>s used
064: * internally).
065: *<p>
066: * This is accopmlished by making a copy of the original map - modifications
067: * made to this copy are not reflected in the original.
068: *
069: * @return The set of keys
070: */
071: public Set stringKeySet() {
072: Iterator iterator = super .keySet().iterator();
073: HashMap stringKeys = new HashMap();
074:
075: while (iterator.hasNext()) {
076: String key = ((CaseBlindString) iterator.next()).toString();
077:
078: stringKeys.put(key, get(key));
079: }
080: return stringKeys.keySet();
081: }
082:
083: /**
084: * Get an Iterator to the String based key set
085: * @return An iterator to the key set
086: */
087: public Iterator stringKeyIterator() {
088: return stringKeySet().iterator();
089: }
090:
091: /*
092: * Overridden HashMap methods
093: */
094:
095: /**
096: * Does the map contain this key?
097: * @param key The key to look up
098: * @return true If the key is present in the map
099: */
100: public boolean containsKey(String key) {
101: return super .containsKey(new CaseBlindString(key));
102: }
103:
104: /**
105: * Fetch a value by name - null keys are not supported
106: * @param key The key to look up
107: * @return The associated value object
108: */
109: public Object get(String key) {
110: return super .get(new CaseBlindString(key));
111: }
112:
113: /**
114: * Add the key/value pair to the map - null values are not supported
115: * @param key The key name
116: * @param value The object to store
117: */
118: public void put(String key, Object value) {
119: super .put(new CaseBlindString(key), value);
120: }
121:
122: /**
123: * Remove a key/value pair from this map
124: * @param key Non-null key to remove
125: */
126: public void remove(String key) {
127: if (key == null) {
128: throw new UnsupportedOperationException("null key");
129: }
130: super .remove(new CaseBlindString(key));
131: }
132:
133: /**
134: * A crude, case insensitive string - used internally to represent
135: * key values. Preserve the originl case, but compare for equality
136: * in a case blind fashion.
137: */
138: public static class CaseBlindString {
139:
140: String string;
141:
142: /**
143: * Constructors
144: */
145: private CaseBlindString() {
146: }
147:
148: public CaseBlindString(String string) {
149: this .string = string;
150: }
151:
152: /**
153: * Fetch the original string
154: * @return The original string
155: */
156: public String toString() {
157: return string;
158: }
159:
160: /**
161: * Case insensitive compare
162: * @return True if the two strings match
163: */
164: public boolean equals(Object object) {
165: if (string == null) {
166: return string == null;
167: }
168: return string.equalsIgnoreCase(((CaseBlindString) object)
169: .toString());
170: }
171:
172: /**
173: * Get a hash code for this case insensitive string
174: * @return Hash code value
175: */
176: public int hashCode() {
177: if (string == null) {
178: return "null".hashCode();
179: }
180: return string.toUpperCase().hashCode();
181: }
182: }
183: }
|