View Javadoc
1 package org.apache.turbine.services.mimetype.util; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache Turbine" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * "Apache Turbine", nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>;. 55 */ 56 57 import java.util.Locale; 58 import java.util.Map; 59 import java.util.HashMap; 60 import java.util.Hashtable; 61 import java.util.Properties; 62 import java.io.File; 63 import java.io.InputStream; 64 import java.io.FileInputStream; 65 import java.io.IOException; 66 67 /*** 68 * This class maintains a set of mappers defining mappings 69 * between locales and the corresponding charsets. The mappings 70 * are defined as properties between locale and charset names. 71 * The definitions can be listed in property files located in user's 72 * home directory, Java home directory or the current class jar. 73 * In addition, this class maintains static default mappings 74 * and constructors support application specific mappings. 75 * 76 * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a> 77 * @version $Id: CharSetMap.java,v 1.1.1.1 2001/08/16 05:09:07 jvanzyl Exp $ 78 */ 79 public class CharSetMap 80 { 81 /*** 82 * The default charset when nothing else is applicable. 83 */ 84 public static final String DEFAULT_CHARSET = "ISO-8859-1"; 85 86 /*** 87 * The name for charset mapper resources. 88 */ 89 public static final String CHARSET_RESOURCE = "charset.properties"; 90 91 /*** 92 * Priorities of available mappers. 93 */ 94 private static final int MAP_CACHE = 0; 95 private static final int MAP_PROG = 1; 96 private static final int MAP_HOME = 2; 97 private static final int MAP_SYS = 3; 98 private static final int MAP_JAR = 4; 99 private static final int MAP_COM = 5; 100 101 /*** 102 * A common charset mapper for languages. 103 */ 104 private static HashMap commonMapper = new HashMap(); 105 static 106 { 107 commonMapper.put("ar","ISO-8859-6"); 108 commonMapper.put("be","ISO-8859-5"); 109 commonMapper.put("bg","ISO-8859-5"); 110 commonMapper.put("ca","ISO-8859-1"); 111 commonMapper.put("cs","ISO-8859-2"); 112 commonMapper.put("da","ISO-8859-1"); 113 commonMapper.put("de","ISO-8859-1"); 114 commonMapper.put("el","ISO-8859-7"); 115 commonMapper.put("en","ISO-8859-1"); 116 commonMapper.put("es","ISO-8859-1"); 117 commonMapper.put("et","ISO-8859-1"); 118 commonMapper.put("fi","ISO-8859-1"); 119 commonMapper.put("fr","ISO-8859-1"); 120 commonMapper.put("hr","ISO-8859-2"); 121 commonMapper.put("hu","ISO-8859-2"); 122 commonMapper.put("is","ISO-8859-1"); 123 commonMapper.put("it","ISO-8859-1"); 124 commonMapper.put("iw","ISO-8859-8"); 125 commonMapper.put("ja","Shift_JIS"); 126 commonMapper.put("ko","EUC-KR"); 127 commonMapper.put("lt","ISO-8859-2"); 128 commonMapper.put("lv","ISO-8859-2"); 129 commonMapper.put("mk","ISO-8859-5"); 130 commonMapper.put("nl","ISO-8859-1"); 131 commonMapper.put("no","ISO-8859-1"); 132 commonMapper.put("pl","ISO-8859-2"); 133 commonMapper.put("pt","ISO-8859-1"); 134 commonMapper.put("ro","ISO-8859-2"); 135 commonMapper.put("ru","ISO-8859-5"); 136 commonMapper.put("sh","ISO-8859-5"); 137 commonMapper.put("sk","ISO-8859-2"); 138 commonMapper.put("sl","ISO-8859-2"); 139 commonMapper.put("sq","ISO-8859-2"); 140 commonMapper.put("sr","ISO-8859-5"); 141 commonMapper.put("sv","ISO-8859-1"); 142 commonMapper.put("tr","ISO-8859-9"); 143 commonMapper.put("uk","ISO-8859-5"); 144 commonMapper.put("zh","GB2312"); 145 commonMapper.put("zh_TW","Big5"); 146 } 147 148 /*** 149 * An array of available charset mappers. 150 */ 151 private Map mappers[] = new Map[6]; 152 153 /*** 154 * Loads mappings from a stream. 155 * 156 * @param input an input stream. 157 * @return the mappings. 158 * @throws IOException for an incorrect stream. 159 */ 160 protected static Map loadStream(InputStream input) 161 throws IOException 162 { 163 Properties props = new Properties(); 164 props.load(input); 165 return new HashMap(props); 166 } 167 168 /*** 169 * Loads mappings from a file. 170 * 171 * @param file a file. 172 * @return the mappings. 173 * @throws IOException for an incorrect file. 174 */ 175 protected static Map loadFile(File file) 176 throws IOException 177 { 178 return loadStream(new FileInputStream(file)); 179 } 180 181 /*** 182 * Loads mappings from a file path. 183 * 184 * @param path a file path. 185 * @return the mappings. 186 * @throws IOException for an incorrect file. 187 */ 188 protected static Map loadPath(String path) 189 throws IOException 190 { 191 return loadFile(new File(path)); 192 } 193 194 /*** 195 * Loads mappings from a resource. 196 * 197 * @param name a resource name. 198 * @return the mappings. 199 */ 200 protected static Map loadResource(String name) 201 { 202 InputStream input = CharSetMap.class.getResourceAsStream(name); 203 if (input != null) 204 { 205 try 206 { 207 return loadStream(input); 208 } 209 catch (IOException x) 210 { 211 return null; 212 } 213 } 214 else 215 { 216 return null; 217 } 218 } 219 220 /*** 221 * Constructs a new charset map with default mappers. 222 */ 223 public CharSetMap() 224 { 225 String path; 226 try 227 { 228 // Check whether the user directory contains mappings. 229 path = System.getProperty("user.home"); 230 if (path != null) 231 { 232 path = path + File.separator + CHARSET_RESOURCE; 233 mappers[MAP_HOME] = loadPath(path); 234 } 235 } 236 catch (Exception x) 237 { 238 } 239 240 try 241 { 242 // Check whether the system directory contains mappings. 243 path = System.getProperty("java.home") + 244 File.separator + "lib" + File.separator + CHARSET_RESOURCE; 245 mappers[MAP_SYS] = loadPath(path); 246 } 247 catch (Exception x) 248 { 249 } 250 251 // Check whether the current class jar contains mappings. 252 mappers[MAP_JAR] = loadResource("/META-INF/" + CHARSET_RESOURCE); 253 254 // Set the common mapper to have the lowest priority. 255 mappers[MAP_COM] = commonMapper; 256 257 // Set the cache mapper to have the highest priority. 258 mappers[MAP_CACHE] = new Hashtable(); 259 } 260 261 /*** 262 * Contructs a charset map from properties. 263 * 264 * @param props charset mapping propeties. 265 */ 266 public CharSetMap(Properties props) 267 { 268 this(); 269 mappers[MAP_PROG] = new HashMap(props); 270 } 271 272 /*** 273 * Contructs a charset map read from a stream. 274 * 275 * @param input an input stream. 276 * @throws IOException for an incorrect stream. 277 */ 278 public CharSetMap(InputStream input) 279 throws IOException 280 { 281 this(); 282 mappers[MAP_PROG] = loadStream(input); 283 } 284 285 /*** 286 * Contructs a charset map read from a property file. 287 * 288 * @param file a property file. 289 * @throws IOException for an incorrect property file. 290 */ 291 public CharSetMap(File file) 292 throws IOException 293 { 294 this(); 295 mappers[MAP_PROG] = loadFile(file); 296 } 297 298 /*** 299 * Contructs a charset map read from a property file path. 300 * 301 * @param path a property file path. 302 * @throws IOException for an incorrect property file. 303 */ 304 public CharSetMap(String path) 305 throws IOException 306 { 307 this(); 308 mappers[MAP_PROG] = loadPath(path); 309 } 310 311 /*** 312 * Sets a locale-charset mapping. 313 * 314 * @param key the key for the charset. 315 * @param charset the corresponding charset. 316 */ 317 public synchronized void setCharSet(String key, 318 String charset) 319 { 320 HashMap mapper = (HashMap) mappers[MAP_PROG]; 321 mapper = mapper != null ? 322 (HashMap) mapper.clone() : new HashMap(); 323 mapper.put(key,charset); 324 mappers[MAP_PROG] = mapper; 325 mappers[MAP_CACHE].clear(); 326 } 327 328 /*** 329 * Gets the charset for a locale. First a locale specific charset 330 * is searched for, then a country specific one and lastly a language 331 * specific one. If none is found, the default charset is returned. 332 * 333 * @param locale the locale. 334 * @return the charset. 335 */ 336 public String getCharSet(Locale locale) 337 { 338 // Check the cache first. 339 String key = locale.toString(); 340 if (key.length() == 0) 341 { 342 key = "__" + locale.getVariant(); 343 if (key.length() == 2) 344 { 345 return DEFAULT_CHARSET; 346 } 347 } 348 String charset = searchCharSet(key); 349 if (charset.length() == 0) 350 { 351 // Not found, perform a full search and update the cache. 352 String[] items = new String[3]; 353 items[2] = locale.getVariant(); 354 items[1] = locale.getCountry(); 355 items[0] = locale.getLanguage(); 356 charset = searchCharSet(items); 357 if (charset.length() == 0) 358 { 359 charset = DEFAULT_CHARSET; 360 } 361 mappers[MAP_CACHE].put(key,charset); 362 } 363 return charset; 364 } 365 366 /*** 367 * Gets the charset for a locale with a variant. The search 368 * is performed in the following order: 369 * "lang"_"country"_"variant"="charset", 370 * _"counry"_"variant"="charset", 371 * "lang"__"variant"="charset", 372 * __"variant"="charset", 373 * "lang"_"country"="charset", 374 * _"country"="charset", 375 * "lang"="charset". 376 * If nothing of the above is found, the default charset is returned. 377 * 378 * @param locale the locale. 379 * @param variant a variant field. 380 * @return the charset. 381 */ 382 public String getCharSet(Locale locale, 383 String variant) 384 { 385 // Check the cache first. 386 if ((variant != null) && 387 (variant.length() > 0)) 388 { 389 String key = locale.toString(); 390 if (key.length() == 0) 391 { 392 key = "__" + locale.getVariant(); 393 if (key.length() > 2) 394 { 395 key += '_' + variant; 396 } 397 else 398 { 399 key += variant; 400 } 401 } 402 else if (locale.getCountry().length() == 0) 403 { 404 key += "__" + variant; 405 } 406 else 407 { 408 key += '_' + variant; 409 } 410 String charset = searchCharSet(key); 411 if (charset.length() == 0) 412 { 413 // Not found, perform a full search and update the cache. 414 String[] items = new String[4]; 415 items[3] = variant; 416 items[2] = locale.getVariant(); 417 items[1] = locale.getCountry(); 418 items[0] = locale.getLanguage(); 419 charset = searchCharSet(items); 420 if (charset.length() == 0) 421 { 422 charset = DEFAULT_CHARSET; 423 } 424 mappers[MAP_CACHE].put(key,charset); 425 } 426 return charset; 427 } 428 else 429 { 430 return getCharSet(locale); 431 } 432 } 433 434 /*** 435 * Gets the charset for a specified key. 436 * 437 * @param key the key for the charset. 438 * @return the found charset or the default one. 439 */ 440 public String getCharSet(String key) 441 { 442 String charset = searchCharSet(key); 443 return charset.length() > 0 ? charset : DEFAULT_CHARSET; 444 } 445 446 /*** 447 * Gets the charset for a specified key. 448 * 449 * @param key the key for the charset. 450 * @param def the default charset if none is found. 451 * @return the found charset or the given default. 452 */ 453 public String getCharSet(String key, 454 String def) 455 { 456 String charset = searchCharSet(key); 457 return charset.length() > 0 ? charset : def; 458 } 459 460 /*** 461 * Searches for a charset for a specified locale. 462 * 463 * @param items an array of locale items. 464 * @return the found charset or an empty string. 465 */ 466 private String searchCharSet(String[] items) 467 { 468 String charset; 469 StringBuffer sb = new StringBuffer(); 470 for (int i = items.length; i > 0; i--) 471 { 472 charset = searchCharSet(items,sb,i); 473 if (charset.length() > 0) 474 { 475 return charset; 476 } 477 sb.setLength(0); 478 } 479 return ""; 480 } 481 482 /*** 483 * Searches recursively for a charset for a specified locale. 484 * 485 * @param items an array of locale items. 486 * @param base a buffer of base items. 487 * @param count the number of items to go through. 488 * @return the found charset or an empty string. 489 */ 490 private String searchCharSet(String[] items, 491 StringBuffer base, 492 int count) 493 { 494 if ((--count >= 0) && 495 (items[count] != null) && 496 (items[count].length() > 0)) 497 { 498 String charset; 499 base.insert(0,items[count]); 500 int length = base.length(); 501 for (int i = count; i > 0; i--) 502 { 503 if ((i == count) || 504 (i <= 1)) 505 { 506 base.insert(0,'_'); 507 length++; 508 } 509 charset = searchCharSet(items,base,i); 510 if (charset.length() > 0) 511 { 512 return charset; 513 } 514 base.delete(0,base.length() - length); 515 } 516 return searchCharSet(base.toString()); 517 } 518 else 519 { 520 return ""; 521 } 522 } 523 524 /*** 525 * Searches for a charset for a specified key. 526 * 527 * @param key the key for the charset. 528 * @return the found charset or an empty string. 529 */ 530 private String searchCharSet(String key) 531 { 532 if ((key != null) && 533 (key.length() > 0)) 534 { 535 // Go through mappers. 536 Map mapper; 537 String charset; 538 for (int i = 0; i < mappers.length; i++) 539 { 540 mapper = mappers[i]; 541 if (mapper != null) 542 { 543 charset = (String) mapper.get(key); 544 if (charset != null) 545 { 546 // Update the cache. 547 if (i > MAP_CACHE) 548 { 549 mappers[MAP_CACHE].put(key,charset); 550 } 551 return charset; 552 } 553 } 554 } 555 556 // Not found, add an empty string to the cache. 557 mappers[MAP_CACHE].put(key,""); 558 } 559 return ""; 560 } 561 562 /*** 563 * Sets a common locale-charset mapping. 564 * 565 * @param key the key for the charset. 566 * @param charset the corresponding charset. 567 */ 568 protected synchronized void setCommonCharSet(String key, 569 String charset) 570 { 571 HashMap mapper = (HashMap) ((HashMap) mappers[MAP_COM]).clone(); 572 mapper.put(key,charset); 573 mappers[MAP_COM] = mapper; 574 mappers[MAP_CACHE].clear(); 575 } 576 }

This page was automatically generated by Maven