1 7 8 22 23 package java.util; 24 25 import java.io.InputStream ; 26 import java.lang.ref.Reference ; 27 import java.lang.ref.ReferenceQueue ; 28 import java.lang.ref.WeakReference ; 29 import sun.misc.SoftCache; 30 31 195 abstract public class ResourceBundle { 196 204 private static final ResourceCacheKey cacheKey = new ResourceCacheKey(); 205 206 207 private static final int INITIAL_CACHE_SIZE = 25; 208 209 210 private static final float CACHE_LOAD_FACTOR = (float)1.0; 211 212 216 private static final int MAX_BUNDLES_SEARCHED = 3; 217 218 227 private static final Hashtable underConstruction = new Hashtable (MAX_BUNDLES_SEARCHED, CACHE_LOAD_FACTOR); 228 229 230 private static final Object NOT_FOUND = new Object (); 231 232 245 private static SoftCache cacheList = new SoftCache(INITIAL_CACHE_SIZE, CACHE_LOAD_FACTOR); 246 247 250 private static ReferenceQueue referenceQueue = new ReferenceQueue (); 251 252 257 protected ResourceBundle parent = null; 258 259 262 private Locale locale = null; 263 264 268 public ResourceBundle() { 269 } 270 271 284 public final String getString(String key) { 285 return (String ) getObject(key); 286 } 287 288 301 public final String [] getStringArray(String key) { 302 return (String []) getObject(key); 303 } 304 305 318 public final Object getObject(String key) { 319 Object obj = handleGetObject(key); 320 if (obj == null) { 321 if (parent != null) { 322 obj = parent.getObject(key); 323 } 324 if (obj == null) 325 throw new MissingResourceException ("Can't find resource for bundle " 326 +this.getClass().getName() 327 +", key "+key, 328 this.getClass().getName(), 329 key); 330 } 331 return obj; 332 } 333 334 341 public Locale getLocale() { 342 return locale; 343 } 344 345 355 private void setLocale(String baseName, String bundleName) { 356 if (baseName.length() == bundleName.length()) { 357 locale = new Locale ("", ""); 358 } else if (baseName.length() < bundleName.length()) { 359 int pos = baseName.length(); 360 String temp = bundleName.substring(pos + 1); 361 pos = temp.indexOf('_'); 362 if (pos == -1) { 363 locale = new Locale (temp, "", ""); 364 return; 365 } 366 367 String language = temp.substring(0, pos); 368 temp = temp.substring(pos + 1); 369 pos = temp.indexOf('_'); 370 if (pos == -1) { 371 locale = new Locale (language, temp, ""); 372 return; 373 } 374 375 String country = temp.substring(0, pos); 376 temp = temp.substring(pos + 1); 377 378 locale = new Locale (language, country, temp); 379 } else { 380 throw new IllegalArgumentException (); 383 } 384 } 385 386 391 private static ClassLoader getLoader() { 392 Class [] stack = getClassContext(); 393 394 Class c = stack[2]; 395 ClassLoader cl = (c == null) ? null : c.getClassLoader(); 396 if (cl == null) { 397 cl = ClassLoader.getSystemClassLoader(); 398 } 399 return cl; 400 } 401 402 private static native Class [] getClassContext(); 403 404 411 protected void setParent( ResourceBundle parent ) { 412 this.parent = parent; 413 } 414 415 425 private static final class ResourceCacheKey implements Cloneable { 426 private LoaderReference loaderRef; 427 private String searchName; 428 private Locale defaultLocale; 429 private int hashCodeCache; 430 431 public boolean equals(Object other) { 432 if (this == other) { 433 return true; 434 } 435 try { 436 final ResourceCacheKey otherEntry = (ResourceCacheKey)other; 437 if (hashCodeCache != otherEntry.hashCodeCache) { 439 return false; 440 } 441 if (!searchName.equals(otherEntry.searchName)) { 443 return false; 444 } 445 if (defaultLocale == null) { 447 if (otherEntry.defaultLocale != null) { 448 return false; 449 } 450 } else { 451 if (!defaultLocale.equals(otherEntry.defaultLocale)) { 452 return false; 453 } 454 } 455 if (loaderRef == null) { 457 return otherEntry.loaderRef == null; 458 } else { 459 Object loaderRefValue = loaderRef.get(); 460 return (otherEntry.loaderRef != null) 461 && (loaderRefValue != null) 465 && (loaderRefValue == otherEntry.loaderRef.get()); 466 } 467 } catch (NullPointerException e) { 468 return false; 469 } catch (ClassCastException e) { 470 return false; 471 } 472 } 473 474 public int hashCode() { 475 return hashCodeCache; 476 } 477 478 public Object clone() { 479 try { 480 ResourceCacheKey clone = (ResourceCacheKey) super.clone(); 481 if (loaderRef != null) { 482 clone.loaderRef = new LoaderReference(loaderRef.get(), referenceQueue, clone); 483 } 484 return clone; 485 } catch (CloneNotSupportedException e) { 486 throw new InternalError (); 488 } 489 } 490 491 public void setKeyValues(ClassLoader loader, String searchName, Locale defaultLocale) { 492 this.searchName = searchName; 493 hashCodeCache = searchName.hashCode(); 494 this.defaultLocale = defaultLocale; 495 if (defaultLocale != null) { 496 hashCodeCache ^= defaultLocale.hashCode(); 497 } 498 if (loader == null) { 499 this.loaderRef = null; 500 } else { 501 loaderRef = new LoaderReference(loader, referenceQueue, this); 502 hashCodeCache ^= loader.hashCode(); 503 } 504 } 505 506 public void clear() { 507 setKeyValues(null, "", null); 508 } 509 } 510 511 516 private static final class LoaderReference extends WeakReference { 517 private ResourceCacheKey cacheKey; 518 519 LoaderReference(Object referent, ReferenceQueue q, ResourceCacheKey key) { 520 super(referent, q); 521 cacheKey = key; 522 } 523 524 ResourceCacheKey getCacheKey() { 525 return cacheKey; 526 } 527 } 528 529 547 public static final ResourceBundle getBundle(String baseName) 548 { 549 return getBundleImpl(baseName, Locale.getDefault(), 550 551 getLoader()); 552 } 553 554 573 public static final ResourceBundle getBundle(String baseName, 574 Locale locale) 575 { 576 return getBundleImpl(baseName, locale, getLoader()); 577 } 578 579 693 public static ResourceBundle getBundle(String baseName, Locale locale, 694 ClassLoader loader) 695 { 696 if (loader == null) { 697 throw new NullPointerException (); 698 } 699 return getBundleImpl(baseName, locale, loader); 700 } 701 702 private static ResourceBundle getBundleImpl(String baseName, Locale locale, 703 ClassLoader loader) 704 { 705 if (baseName == null) { 706 throw new NullPointerException (); 707 } 708 709 String bundleName = baseName; 711 String localeSuffix = locale.toString(); 712 if (localeSuffix.length() > 0) { 713 bundleName += "_" + localeSuffix; 714 } else if (locale.getVariant().length() > 0) { 715 bundleName += "___" + locale.getVariant(); 718 } 719 720 Locale defaultLocale = Locale.getDefault(); 723 724 Object lookup = findBundleInCache(loader, bundleName, defaultLocale); 725 if (lookup == NOT_FOUND) { 726 throwMissingResourceException(baseName, locale); 727 } else if (lookup != null) { 728 return (ResourceBundle )lookup; 729 } 730 731 735 740 Object parent = NOT_FOUND; 741 try { 742 Object root = findBundle(loader, baseName, defaultLocale, baseName, null); 744 if (root == null) { 745 putBundleInCache(loader, baseName, defaultLocale, NOT_FOUND); 746 root = NOT_FOUND; 747 } 748 749 final Vector names = calculateBundleNames(baseName, locale); 753 Vector bundlesFound = new Vector (MAX_BUNDLES_SEARCHED); 754 boolean foundInMainBranch = (root != NOT_FOUND && names.size() == 0); 757 758 if (!foundInMainBranch) { 759 parent = root; 760 for (int i = 0; i < names.size(); i++) { 761 bundleName = (String )names.elementAt(i); 762 lookup = findBundle(loader, bundleName, defaultLocale, baseName, parent); 763 bundlesFound.addElement(lookup); 764 if (lookup != null) { 765 parent = lookup; 766 foundInMainBranch = true; 767 } 768 } 769 } 770 parent = root; 771 if (!foundInMainBranch) { 772 final Vector fallbackNames = calculateBundleNames(baseName, defaultLocale); 774 for (int i = 0; i < fallbackNames.size(); i++) { 775 bundleName = (String )fallbackNames.elementAt(i); 776 if (names.contains(bundleName)) { 777 break; 779 } 780 lookup = findBundle(loader, bundleName, defaultLocale, baseName, parent); 781 if (lookup != null) { 782 parent = lookup; 783 } else { 784 putBundleInCache(loader, bundleName, defaultLocale, parent); 787 } 788 } 789 } 790 parent = propagate(loader, names, bundlesFound, defaultLocale, parent); 792 } catch (Exception e) { 793 cleanUpConstructionList(); 796 throwMissingResourceException(baseName, locale); 797 } catch (Error e) { 798 cleanUpConstructionList(); 802 throw e; 803 } 804 if (parent == NOT_FOUND) { 805 throwMissingResourceException(baseName, locale); 806 } 807 return (ResourceBundle )parent; 808 } 809 810 819 private static Object propagate(ClassLoader loader, Vector names, 820 Vector bundlesFound, Locale defaultLocale, Object parent) { 821 for (int i = 0; i < names.size(); i++) { 822 final String bundleName = (String )names.elementAt(i); 823 final Object lookup = bundlesFound.elementAt(i); 824 if (lookup == null) { 825 putBundleInCache(loader, bundleName, defaultLocale, parent); 826 } else { 827 parent = lookup; 828 } 829 } 830 return parent; 831 } 832 833 834 private static void throwMissingResourceException(String baseName, Locale locale) 835 throws MissingResourceException { 836 throw new MissingResourceException ("Can't find bundle for base name " 837 + baseName + ", locale " + locale, 838 baseName + "_" + locale,""); 839 } 840 841 846 private static void cleanUpConstructionList() { 847 synchronized (cacheList) { 848 final Collection entries = underConstruction.values(); 849 final Thread thisThread = Thread.currentThread(); 850 while (entries.remove(thisThread)) { 851 } 852 cacheList.notifyAll(); 855 } 856 } 857 858 872 private static Object findBundle(ClassLoader loader, String bundleName, Locale defaultLocale, 873 String baseName, Object parent) { 874 Object result; 875 synchronized (cacheList) { 876 Reference ref = referenceQueue.poll(); 881 while (ref != null) { 882 cacheList.remove(((LoaderReference) ref).getCacheKey()); 883 ref = referenceQueue.poll(); 884 } 885 886 cacheKey.setKeyValues(loader, bundleName, defaultLocale); 888 result = cacheList.get(cacheKey); 889 if (result != null) { 890 cacheKey.clear(); 891 return result; 892 } 893 Thread builder = (Thread ) underConstruction.get(cacheKey); 898 boolean beingBuilt = (builder != null && builder != Thread.currentThread()); 899 if (beingBuilt) { 901 while (beingBuilt) { 903 cacheKey.clear(); 904 try { 905 cacheList.wait(); 907 } catch (InterruptedException e) { 908 } 909 cacheKey.setKeyValues(loader, bundleName, defaultLocale); 910 beingBuilt = underConstruction.containsKey(cacheKey); 911 } 912 result = cacheList.get(cacheKey); 914 if (result != null) { 915 cacheKey.clear(); 916 return result; 917 } 918 } 919 final Object key = cacheKey.clone(); 922 underConstruction.put(key, Thread.currentThread()); 923 cacheKey.clear(); 925 } 926 927 result = loadBundle(loader, bundleName, defaultLocale); 929 if (result != null) { 930 boolean constructing; 933 synchronized (cacheList) { 934 cacheKey.setKeyValues(loader, bundleName, defaultLocale); 935 constructing = underConstruction.get(cacheKey) == Thread.currentThread(); 936 cacheKey.clear(); 937 } 938 if (constructing) { 939 final ResourceBundle bundle = (ResourceBundle )result; 941 if (parent != NOT_FOUND && bundle.parent == null) { 942 bundle.setParent((ResourceBundle ) parent); 943 } 944 bundle.setLocale(baseName, bundleName); 945 putBundleInCache(loader, bundleName, defaultLocale, result); 946 } 947 } 948 return result; 949 } 950 951 960 private static Vector calculateBundleNames(String baseName, Locale locale) { 961 final Vector result = new Vector (MAX_BUNDLES_SEARCHED); 962 final String language = locale.getLanguage(); 963 final int languageLength = language.length(); 964 final String country = locale.getCountry(); 965 final int countryLength = country.length(); 966 final String variant = locale.getVariant(); 967 final int variantLength = variant.length(); 968 969 if (languageLength + countryLength + variantLength == 0) { 970 return result; 972 } 973 final StringBuffer temp = new StringBuffer (baseName); 974 temp.append('_'); 975 temp.append(language); 976 if (languageLength > 0) { 977 result.addElement(temp.toString()); 978 } 979 980 if (countryLength + variantLength == 0) { 981 return result; 982 } 983 temp.append('_'); 984 temp.append(country); 985 if (countryLength > 0) { 986 result.addElement(temp.toString()); 987 } 988 989 if (variantLength == 0) { 990 return result; 991 } 992 temp.append('_'); 993 temp.append(variant); 994 result.addElement(temp.toString()); 995 996 return result; 997 } 998 999 1007 private static Object findBundleInCache(ClassLoader loader, String bundleName, 1008 Locale defaultLocale) { 1009 synchronized (cacheList) { 1011 cacheKey.setKeyValues(loader, bundleName, defaultLocale); 1012 Object result = cacheList.get(cacheKey); 1013 cacheKey.clear(); 1014 return result; 1015 } 1016 } 1017 1018 1023 private static void putBundleInCache(ClassLoader loader, String bundleName, 1024 Locale defaultLocale, Object value) { 1025 synchronized (cacheList) { 1028 cacheKey.setKeyValues(loader, bundleName, defaultLocale); 1029 cacheList.put(cacheKey.clone(), value); 1030 underConstruction.remove(cacheKey); 1031 cacheKey.clear(); 1032 cacheList.notifyAll(); 1034 } 1035 } 1036 1037 1048 private static Object loadBundle(final ClassLoader loader, String bundleName, Locale defaultLocale) { 1049 try { 1051 Class bundleClass; 1052 if (loader != null) { 1053 bundleClass = loader.loadClass(bundleName); 1054 } else { 1055 bundleClass = Class.forName(bundleName); 1056 } 1057 if (ResourceBundle .class.isAssignableFrom(bundleClass)) { 1058 Object myBundle = bundleClass.newInstance(); 1059 Object otherBundle = findBundleInCache(loader, bundleName, defaultLocale); 1063 if (otherBundle != null) { 1064 return otherBundle; 1065 } else { 1066 return myBundle; 1067 } 1068 } 1069 } catch (Exception e) { 1070 } catch (LinkageError e) { 1071 } 1072 1073 final String resName = bundleName.replace('.', '/') + ".properties"; 1075 InputStream stream = (InputStream )java.security.AccessController.doPrivileged( 1076 new java.security.PrivilegedAction () { 1077 public Object run() { 1078 if (loader != null) { 1079 return loader.getResourceAsStream(resName); 1080 } else { 1081 return ClassLoader.getSystemResourceAsStream(resName); 1082 } 1083 } 1084 } 1085 ); 1086 1087 if (stream != null) { 1088 stream = new java.io.BufferedInputStream (stream); 1090 try { 1091 return new PropertyResourceBundle (stream); 1092 } catch (Exception e) { 1093 } finally { 1094 try { 1095 stream.close(); 1096 } catch (Exception e) { 1097 } 1102 } 1103 } 1104 return null; 1105 } 1106 1107 1116 protected abstract Object handleGetObject(String key); 1117 1118 1122 public abstract Enumeration <String > getKeys(); 1123} 1124 | Popular Tags |