1 /*
2 * @(#)CIHashtable.java 0.3-3 06/05/2001
3 *
4 * This file is part of the HTTPClient package
5 * Copyright (C) 1996-2001 Ronald Tschalär
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307, USA
21 *
22 * For questions, suggestions, bug-reports, enhancement-requests etc.
23 * I may be contacted at:
24 *
25 * ronald@innovation.ch
26 *
27 * The HTTPClient's home page is located at:
28 *
29 * http://www.innovation.ch/java/HTTPClient/
30 *
31 * This file contains modifications for use with "The Grinder"
32 * (http://grinder.sourceforge.net) under the terms of the LGPL. They
33 * are marked below with the comment "GRINDER MODIFICATION".
34 */
35
36 package HTTPClient;
37
38 import java.util.Hashtable;
39 import java.util.Enumeration;
40
41 /**
42 * This class implements a Hashtable with case-insensitive Strings as keys.
43 *
44 * @version 0.3-3 06/05/2001
45 * @author Ronald Tschalär
46 */
47 class CIHashtable extends Hashtable
48 {
49 // Constructors
50
51 /**
52 * Create a new CIHashtable with the specified initial capacity and the
53 * specified load factor.
54 *
55 * @param intialCapacity the initial number of buckets
56 * @param loadFactor a number between 0.0 and 1.0
57 * @see java.util.Hashtable(int, float)
58 */
59 public CIHashtable(int initialCapacity, float loadFactor)
60 {
61 super(initialCapacity, loadFactor);
62 }
63
64
65 /**
66 * Create a new CIHashtable with the specified initial capacity.
67 *
68 * @param intialCapacity the initial number of buckets
69 * @see java.util.Hashtable(int)
70 */
71 public CIHashtable(int initialCapacity)
72 {
73 super(initialCapacity);
74 }
75
76
77 /**
78 * Create a new CIHashtable with a default initial capacity.
79 *
80 * @see java.util.Hashtable()
81 */
82 public CIHashtable()
83 {
84 super();
85 }
86
87
88 // Methods
89
90 /**
91 * Retrieves the object associated with the specified key. The key lookup
92 * is case-insensitive.
93 *
94 * @param key the key
95 * @return the object associated with the key, or null if none found.
96 * @see java.util.Hashtable.get(Object)
97 */
98 public Object get(String key)
99 {
100 return super.get(new CIString(key));
101 }
102
103
104 /**
105 * Stores the specified object with the specified key.
106 *
107 * @param key the key
108 * @param value the object to be associated with the key
109 * @return the object previously associated with the key, or null if
110 * there was none.
111 * @see java.util.Hashtable.put(Object, Object)
112 */
113 public Object put(String key, Object value)
114 {
115 return super.put(new CIString(key), value);
116 }
117
118
119 /**
120 * Looks whether any object is associated with the specified key. The
121 * key lookup is case insensitive.
122 *
123 * @param key the key
124 * @return true is there is an object associated with key, false otherwise
125 * @see java.util.Hashtable.containsKey(Object)
126 */
127 public boolean containsKey(String key)
128 {
129 return super.containsKey(new CIString(key));
130 }
131
132
133 /**
134 * Removes the object associated with this key from the Hashtable. The
135 * key lookup is case insensitive.
136 *
137 * @param key the key
138 * @return the object associated with this key, or null if there was none.
139 * @see java.util.Hashtable.remove(Object)
140 */
141 public Object remove(String key)
142 {
143 return super.remove(new CIString(key));
144 }
145
146
147 /**
148 * Returns an enumeration of all the keys in the Hashtable.
149 *
150 * @return the requested Enumerator
151 * @see java.util.Hashtable.keys(Object)
152 */
153 public Enumeration keys()
154 {
155 return new CIHashtableEnumeration(super.keys());
156 }
157 }
158
159
160 /**
161 * A simple enumerator which delegates everything to the real enumerator.
162 * If a CIString element is returned, then the string it represents is
163 * returned instead.
164 */
165 final class CIHashtableEnumeration implements Enumeration
166 {
167 Enumeration HTEnum;
168
169 /** ++GRINDER MODIFICIATION **/
170 // public CIHashtableEnumeration(Enumeration enum)
171 // {
172 // HTEnum = enum;
173 // }
174 public CIHashtableEnumeration(Enumeration e)
175 {
176 HTEnum = e;
177 }
178 /** --GRINDER MODIFICIATION **/
179
180 public boolean hasMoreElements()
181 {
182 return HTEnum.hasMoreElements();
183 }
184
185 public Object nextElement()
186 {
187 Object tmp = HTEnum.nextElement();
188 if (tmp instanceof CIString)
189 return ((CIString) tmp).getString();
190
191 return tmp;
192 }
193 }
194
195
196 /**
197 * This class' raison d'etre is that I want to use a Hashtable using
198 * Strings as keys and I want the lookup be case insensitive, but I
199 * also want to be able retrieve the keys with original case (otherwise
200 * I could just use toLowerCase() in the get() and put()). Since the
201 * class String is final we create a new class that holds the string
202 * and overrides the methods hashCode() and equals().
203 */
204 final class CIString
205 {
206 /** the string */
207 private String string;
208
209 /** the hash code */
210 private int hash;
211
212
213 /** the constructor */
214 public CIString(String string)
215 {
216 this.string = string;
217 this.hash = calcHashCode(string);
218 }
219
220 /** return the original string */
221 public final String getString()
222 {
223 return string;
224 }
225
226 /** the hash code was precomputed */
227 public int hashCode()
228 {
229 return hash;
230 }
231
232
233 /**
234 * We smash case before calculation so that the hash code is
235 * "case insensitive". This is based on code snarfed from
236 * java.lang.String.hashCode().
237 */
238 private static final int calcHashCode(String str)
239 {
240 int hash = 0;
241 char llc[] = lc;
242 int len = str.length();
243
244 for (int idx= 0; idx<len; idx++)
245 hash = 31*hash + llc[str.charAt(idx)];
246
247 return hash;
248 }
249
250
251 /**
252 * Uses the case insensitive comparison.
253 */
254 public boolean equals(Object obj)
255 {
256 if (obj != null)
257 {
258 if (obj instanceof CIString)
259 return string.equalsIgnoreCase(((CIString) obj).string);
260
261 if (obj instanceof String)
262 return string.equalsIgnoreCase((String) obj);
263 }
264
265 return false;
266 }
267
268 /**
269 * Just return the internal string.
270 */
271 public String toString()
272 {
273 return string;
274 }
275
276
277 private static final char[] lc = new char[256];
278
279 static
280 {
281 // just ISO-8859-1
282 for (char idx=0; idx<256; idx++)
283 lc[idx] = Character.toLowerCase(idx);
284 }
285 }