001:/*
002: * @(#)CIHashtable.java 0.3-2 18/06/1999
003: *
004: * This file is part of the HTTPClient package
005: * Copyright (C) 1996-1999 Ronald Tschalär
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free
019: * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
020: * MA 02111-1307, USA
021: *
022: * For questions, suggestions, bug-reports, enhancement-requests etc.
023: * I may be contacted at:
024: *
025: * ronald@innovation.ch
026: *
027: */
028:
029:package HTTPClient;
030:
031:
032:import java.util.Hashtable;
033:import java.util.Enumeration;
034:
035:/**
036: * This class implements a Hashtable with case-insensitive Strings as keys.
037: *
038: * @version 0.3-2 18/06/1999
039: * @author Ronald Tschalär
040: */
041:
042:class CIHashtable extends Hashtable
043:{
044: // Constructors
045:
046: /**
047: * Create a new CIHashtable with the specified initial capacity and the
048: * specified load factor.
049: *
050: * @param intialCapacity the initial number of buckets
051: * @param loadFactor a number between 0.0 and 1.0
052: * @see java.util.Hashtable(int, float)
053: */
054: public CIHashtable(int initialCapacity, float loadFactor)
055: {
056: super (initialCapacity, loadFactor);
057: }
058:
059:
060: /**
061: * Create a new CIHashtable with the specified initial capacity.
062: *
063: * @param intialCapacity the initial number of buckets
064: * @see java.util.Hashtable(int)
065: */
066: public CIHashtable(int initialCapacity)
067: {
068: super (initialCapacity);
069: }
070:
071:
072: /**
073: * Create a new CIHashtable with a default initial capacity.
074: *
075: * @see java.util.Hashtable()
076: */
077: public CIHashtable()
078: {
079: super ();
080: }
081:
082:
083: // Methods
084:
085: /**
086: * Retrieves the object associated with the specified key. The key lookup
087: * is case-insensitive.
088: *
089: * @param key the key
090: * @return the object associated with the key, or null if none found.
091: * @see java.util.Hashtable.get(Object)
092: */
093: public Object get(String key)
094: {
095: return super .get(new CIString(key));
096: }
097:
098:
099: /**
100: * Stores the specified object with the specified key.
101: *
102: * @param key the key
103: * @param value the object to be associated with the key
104: * @return the object previously associated with the key, or null if
105: * there was none.
106: * @see java.util.Hashtable.put(Object, Object)
107: */
108: public Object put(String key, Object value)
109: {
110: return super .put(new CIString(key), value);
111: }
112:
113:
114: /**
115: * Looks whether any object is associated with the specified key. The
116: * key lookup is case insensitive.
117: *
118: * @param key the key
119: * @return true is there is an object associated with key, false otherwise
120: * @see java.util.Hashtable.containsKey(Object)
121: */
122: public boolean containsKey(String key)
123: {
124: return super .contains(new CIString(key));
125: }
126:
127:
128: /**
129: * Removes the object associated with this key from the Hashtable. The
130: * key lookup is case insensitive.
131: *
132: * @param key the key
133: * @return the object associated with this key, or null if there was none.
134: * @see java.util.Hashtable.remove(Object)
135: */
136: public Object remove(String key)
137: {
138: return super .remove(new CIString(key));
139: }
140:
141:
142: /**
143: * Returns an enumeration of all the keys in the Hashtable.
144: *
145: * @return the requested Enumerator
146: * @see java.util.Hashtable.keys(Object)
147: */
148: public Enumeration keys()
149: {
150: return new CIHashtableEnumeration(super .keys());
151: }
152:}
153:
154:
155:/**
156: * A simple enumerator which delegates everything to the real enumerator.
157: * If a CIString element is returned, then the string it represents is
158: * returned instead.
159: */
160:final class CIHashtableEnumeration implements Enumeration
161:{
162: Enumeration HTEnum;
163:
164: public CIHashtableEnumeration(Enumeration enum)
165: {
166: HTEnum = enum;
167: }
168:
169: public boolean hasMoreElements()
170: {
171: return HTEnum.hasMoreElements();
172: }
173:
174: public Object nextElement()
175: {
176: Object tmp = HTEnum.nextElement();
177: if (tmp instanceof CIString)
178: return ((CIString) tmp).getString();
179:
180: return tmp;
181: }
182:}
183:
184:
185:/**
186: * This class' raison d'etre is that I want to use a Hashtable using
187: * Strings as keys and I want the lookup be case insensitive, but I
188: * also want to be able retrieve the keys with original case (otherwise
189: * I could just use toLowerCase() in the get() and put()). Since the
190: * class String is final we create a new class that holds the string
191: * and overrides the methods hashCode() and equals().
192: */
193:final class CIString
194:{
195: /** the string */
196: private String string;
197:
198: /** the hash code */
199: private int hash;
200:
201:
202: /** the constructor */
203: public CIString(String string)
204: {
205: this .string = string;
206: this .hash = calcHashCode(string);
207: }
208:
209: /** return the original string */
210: public final String getString()
211: {
212: return string;
213: }
214:
215: /** the hash code was precomputed */
216: public int hashCode()
217: {
218: return hash;
219: }
220:
221:
222: /**
223: * We smash case before calculation so that the hash code is
224: * "case insensitive". This is based on code snarfed from
225: * java.lang.String.hashCode().
226: */
227: private static final int calcHashCode(String str)
228: {
229: int hash = 0;
230: char llc[] = lc;
231: int len = str.length();
232:
233: for (int idx= 0; idx<len; idx++)
234: hash = 31*hash + llc[str.charAt(idx)];
235:
236: return hash;
237: }
238:
239:
240: /**
241: * Uses the case insensitive comparison.
242: */
243: public boolean equals(Object obj)
244: {
245: if (obj != null)
246: {
247: if (obj instanceof CIString)
248: return string.equalsIgnoreCase(((CIString) obj).string);
249:
250: if (obj instanceof String)
251: return string.equalsIgnoreCase((String) obj);
252: }
253:
254: return false;
255: }
256:
257: /**
258: * Just return the internal string.
259: */
260: public String toString()
261: {
262: return string;
263: }
264:
265:
266: private static final char[] lc = new char[256];
267:
268: static
269: {
270: // just ISO-8859-1
271: for (char idx=0; idx<256; idx++)
272: lc[idx] = Character.toLowerCase(idx);
273: }
274:}
|