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 }