1 7 package com.ibm.icu.impl; 8 9 11 import java.lang.ref.SoftReference ; 12 import java.util.ArrayList ; 13 import java.util.Collections ; 14 import java.util.Comparator ; 15 import java.util.EventListener ; 16 import java.util.HashMap ; 17 import java.util.HashSet ; 18 import java.util.Iterator ; 19 import java.util.List ; 20 import java.util.ListIterator ; 21 import java.util.Locale ; 22 import java.util.Map ; 23 import java.util.Map.Entry; 24 import java.util.Set ; 25 import java.util.SortedMap ; 26 import java.util.TreeMap ; 27 28 import com.ibm.icu.util.ULocale; 29 30 94 public class ICUService extends ICUNotifier { 95 98 protected final String name; 99 100 103 public ICUService() { 104 name = ""; 105 } 106 107 private static final boolean DEBUG = ICUDebug.enabled("service"); 108 111 public ICUService(String name) { 112 this.name = name; 113 } 114 115 120 private final ICURWLock factoryLock = new ICURWLock(); 121 122 125 private final List factories = new ArrayList (); 126 127 131 private int defaultSize = 0; 132 133 152 public static class Key { 153 private final String id; 154 155 158 public Key(String id) { 159 this.id = id; 160 } 161 162 165 public final String id() { 166 return id; 167 } 168 169 173 public String canonicalID() { 174 return id; 175 } 176 177 181 public String currentID() { 182 return canonicalID(); 183 } 184 185 194 public String currentDescriptor() { 195 return "/" + currentID(); 196 } 197 198 205 public boolean fallback() { 206 return false; 207 } 208 209 213 public boolean isFallbackOf(String id) { 214 return canonicalID().equals(id); 215 } 216 } 217 218 224 public static interface Factory { 225 226 238 public Object create(Key key, ICUService service); 239 240 249 public void updateVisibleIDs(Map result); 250 251 257 public String getDisplayName(String id, ULocale locale); 258 } 259 260 269 public static class SimpleFactory implements Factory { 270 protected Object instance; 271 protected String id; 272 protected boolean visible; 273 274 278 public SimpleFactory(Object instance, String id) { 279 this(instance, id, true); 280 } 281 282 287 public SimpleFactory(Object instance, String id, boolean visible) { 288 if (instance == null || id == null) { 289 throw new IllegalArgumentException ("Instance or id is null"); 290 } 291 this.instance = instance; 292 this.id = id; 293 this.visible = visible; 294 } 295 296 300 public Object create(Key key, ICUService service) { 301 if (id.equals(key.currentID())) { 302 return instance; 303 } 304 return null; 305 } 306 307 311 public void updateVisibleIDs(Map result) { 312 if (visible) { 313 result.put(id, this); 314 } else { 315 result.remove(id); 316 } 317 } 318 319 324 public String getDisplayName(String id, ULocale locale) { 325 return (visible && this.id.equals(id)) ? id : null; 326 } 327 328 331 public String toString() { 332 StringBuffer buf = new StringBuffer (super.toString()); 333 buf.append(", id: "); 334 buf.append(id); 335 buf.append(", visible: "); 336 buf.append(visible); 337 return buf.toString(); 338 } 339 } 340 341 345 public Object get(String descriptor) { 346 return getKey(createKey(descriptor), null); 347 } 348 349 353 public Object get(String descriptor, String [] actualReturn) { 354 if (descriptor == null) { 355 throw new NullPointerException ("descriptor must not be null"); 356 } 357 return getKey(createKey(descriptor), actualReturn); 358 } 359 360 363 public Object getKey(Key key) { 364 return getKey(key, null); 365 } 366 367 382 public Object getKey(Key key, String [] actualReturn) { 383 return getKey(key, actualReturn, null); 384 } 385 386 389 public Object getKey(Key key, String [] actualReturn, Factory factory) { 390 if (factories.size() == 0) { 391 return handleDefault(key, actualReturn); 392 } 393 394 if (DEBUG) System.out.println("Service: " + name + " key: " + key.canonicalID()); 395 396 CacheEntry result = null; 397 if (key != null) { 398 try { 399 factoryLock.acquireRead(); 403 404 Map cache = null; 405 SoftReference cref = cacheref; if (cref != null) { 407 if (DEBUG) System.out.println("Service " + name + " ref exists"); 408 cache = (Map )cref.get(); 409 } 410 if (cache == null) { 411 if (DEBUG) System.out.println("Service " + name + " cache was empty"); 412 cache = Collections.synchronizedMap(new HashMap ()); 415 cref = new SoftReference (cache); 417 } 418 419 String currentDescriptor = null; 420 ArrayList cacheDescriptorList = null; 421 boolean putInCache = false; 422 423 int NDebug = 0; 424 425 int startIndex = 0; 426 int limit = factories.size(); 427 boolean cacheResult = true; 428 if (factory != null) { 429 for (int i = 0; i < limit; ++i) { 430 if (factory == factories.get(i)) { 431 startIndex = i + 1; 432 break; 433 } 434 } 435 if (startIndex == 0) { 436 throw new IllegalStateException ("Factory " + factory + "not registered with service: " + this); 437 } 438 cacheResult = false; 439 } 440 441 outer: 442 do { 443 currentDescriptor = key.currentDescriptor(); 444 if (DEBUG) System.out.println(name + "[" + NDebug++ + "] looking for: " + currentDescriptor); 445 result = (CacheEntry)cache.get(currentDescriptor); 446 if (result != null) { 447 if (DEBUG) System.out.println(name + " found with descriptor: " + currentDescriptor); 448 break outer; 449 } else { 450 if (DEBUG) System.out.println("did not find: " + currentDescriptor + " in cache"); 451 } 452 453 putInCache = cacheResult; 457 458 int index = startIndex; 460 while (index < limit) { 461 Factory f = (Factory)factories.get(index++); 462 if (DEBUG) System.out.println("trying factory[" + (index-1) + "] " + f.toString()); 463 Object service = f.create(key, this); 464 if (service != null) { 465 result = new CacheEntry(currentDescriptor, service); 466 if (DEBUG) System.out.println(name + " factory supported: " + currentDescriptor + ", caching"); 467 break outer; 468 } else { 469 if (DEBUG) System.out.println("factory did not support: " + currentDescriptor); 470 } 471 } 472 473 if (cacheDescriptorList == null) { 479 cacheDescriptorList = new ArrayList (5); 480 } 481 cacheDescriptorList.add(currentDescriptor); 482 483 } while (key.fallback()); 484 485 if (result != null) { 486 if (putInCache) { 487 if (DEBUG) System.out.println("caching '" + result.actualDescriptor + "'"); 488 cache.put(result.actualDescriptor, result); 489 if (cacheDescriptorList != null) { 490 Iterator iter = cacheDescriptorList.iterator(); 491 while (iter.hasNext()) { 492 String desc = (String )iter.next(); 493 if (DEBUG) System.out.println(name + " adding descriptor: '" + desc + "' for actual: '" + result.actualDescriptor + "'"); 494 495 cache.put(desc, result); 496 } 497 } 498 cacheref = cref; 503 } 504 505 if (actualReturn != null) { 506 if (result.actualDescriptor.indexOf("/") == 0) { 508 actualReturn[0] = result.actualDescriptor.substring(1); 509 } else { 510 actualReturn[0] = result.actualDescriptor; 511 } 512 } 513 514 if (DEBUG) System.out.println("found in service: " + name); 515 516 return result.service; 517 } 518 } 519 finally { 520 factoryLock.releaseRead(); 521 } 522 } 523 524 if (DEBUG) System.out.println("not found in service: " + name); 525 526 return handleDefault(key, actualReturn); 527 } 528 private SoftReference cacheref; 529 530 private static final class CacheEntry { 533 final String actualDescriptor; 534 final Object service; 535 CacheEntry(String actualDescriptor, Object service) { 536 this.actualDescriptor = actualDescriptor; 537 this.service = service; 538 } 539 } 540 541 542 546 protected Object handleDefault(Key key, String [] actualIDReturn) { 547 return null; 548 } 549 550 554 public Set getVisibleIDs() { 555 return getVisibleIDs(null); 556 } 557 558 569 public Set getVisibleIDs(String matchID) { 570 Set result = getVisibleIDMap().keySet(); 571 572 Key fallbackKey = createKey(matchID); 573 574 if (fallbackKey != null) { 575 Set temp = new HashSet (result.size()); 576 Iterator iter = result.iterator(); 577 while (iter.hasNext()) { 578 String id = (String )iter.next(); 579 if (fallbackKey.isFallbackOf(id)) { 580 temp.add(id); 581 } 582 } 583 result = temp; 584 } 585 return result; 586 } 587 588 591 private Map getVisibleIDMap() { 592 Map idcache = null; 593 SoftReference ref = idref; 594 if (ref != null) { 595 idcache = (Map )ref.get(); 596 } 597 while (idcache == null) { 598 synchronized (this) { if (ref == idref || idref == null) { 600 try { 603 factoryLock.acquireRead(); 604 idcache = new HashMap (); 605 ListIterator lIter = factories.listIterator(factories.size()); 606 while (lIter.hasPrevious()) { 607 Factory f = (Factory)lIter.previous(); 608 f.updateVisibleIDs(idcache); 609 } 610 idcache = Collections.unmodifiableMap(idcache); 611 idref = new SoftReference (idcache); 612 } 613 finally { 614 factoryLock.releaseRead(); 615 } 616 } else { 617 ref = idref; 621 idcache = (Map )ref.get(); 622 } 623 } 624 } 625 626 return idcache; 627 } 628 private SoftReference idref; 629 630 634 public String getDisplayName(String id) { 635 return getDisplayName(id, ULocale.getDefault()); 636 } 637 638 643 public String getDisplayName(String id, ULocale locale) { 644 Map m = getVisibleIDMap(); 645 Factory f = (Factory)m.get(id); 646 if (f != null) { 647 return f.getDisplayName(id, locale); 648 } 649 650 Key key = createKey(id); 651 while (key.fallback()) { 652 f = (Factory)m.get(key.currentID()); 653 if (f != null) { 654 return f.getDisplayName(id, locale); 655 } 656 } 657 658 return null; 659 } 660 661 666 public SortedMap getDisplayNames() { 667 ULocale locale = ULocale.getDefault(); 668 return getDisplayNames(locale, null, null); 669 } 670 671 675 public SortedMap getDisplayNames(ULocale locale) { 676 return getDisplayNames(locale, null, null); 677 } 678 679 683 public SortedMap getDisplayNames(ULocale locale, Comparator com) { 684 return getDisplayNames(locale, com, null); 685 } 686 687 691 public SortedMap getDisplayNames(ULocale locale, String matchID) { 692 return getDisplayNames(locale, null, matchID); 693 } 694 695 705 public SortedMap getDisplayNames(ULocale locale, Comparator com, String matchID) { 706 SortedMap dncache = null; 707 LocaleRef ref = dnref; 708 709 if (ref != null) { 710 dncache = ref.get(locale, com); 711 } 712 713 while (dncache == null) { 714 synchronized (this) { 715 if (ref == dnref || dnref == null) { 716 dncache = new TreeMap (com); 718 Map m = getVisibleIDMap(); 719 Iterator ei = m.entrySet().iterator(); 720 while (ei.hasNext()) { 721 Entry e = (Entry)ei.next(); 722 String id = (String )e.getKey(); 723 Factory f = (Factory)e.getValue(); 724 dncache.put(f.getDisplayName(id, locale), id); 725 } 726 727 dncache = Collections.unmodifiableSortedMap(dncache); 728 dnref = new LocaleRef(dncache, locale, com); 729 } else { 730 ref = dnref; 731 dncache = ref.get(locale, com); 732 } 733 } 734 } 735 736 Key matchKey = createKey(matchID); 737 if (matchKey == null) { 738 return dncache; 739 } 740 741 SortedMap result = new TreeMap (dncache); 742 Iterator iter = result.entrySet().iterator(); 743 while (iter.hasNext()) { 744 Entry e = (Entry)iter.next(); 745 if (!matchKey.isFallbackOf((String )e.getValue())) { 746 iter.remove(); 747 } 748 } 749 return result; 750 } 751 752 private static class LocaleRef { 755 private final ULocale locale; 756 private SoftReference ref; 757 private Comparator com; 758 759 LocaleRef(Map dnCache, ULocale locale, Comparator com) { 760 this.locale = locale; 761 this.com = com; 762 this.ref = new SoftReference (dnCache); 763 } 764 765 766 SortedMap get(ULocale locale, Comparator com) { 767 SortedMap m = (SortedMap )ref.get(); 768 if (m != null && 769 this.locale.equals(locale) && 770 (this.com == com || (this.com != null && this.com.equals(com)))) { 771 772 return m; 773 } 774 return null; 775 } 776 } 777 private LocaleRef dnref; 778 779 784 public final List factories() { 785 try { 786 factoryLock.acquireRead(); 787 return new ArrayList (factories); 788 } 789 finally{ 790 factoryLock.releaseRead(); 791 } 792 } 793 794 798 public Factory registerObject(Object obj, String id) { 799 return registerObject(obj, id, true); 800 } 801 802 807 public Factory registerObject(Object obj, String id, boolean visible) { 808 String canonicalID = createKey(id).canonicalID(); 809 return registerFactory(new SimpleFactory(obj, canonicalID, visible)); 810 } 811 812 817 public final Factory registerFactory(Factory factory) { 818 if (factory == null) { 819 throw new NullPointerException (); 820 } 821 try { 822 factoryLock.acquireWrite(); 823 factories.add(0, factory); 824 clearCaches(); 825 } 826 finally { 827 factoryLock.releaseWrite(); 828 } 829 notifyChanged(); 830 return factory; 831 } 832 833 838 public final boolean unregisterFactory(Factory factory) { 839 if (factory == null) { 840 throw new NullPointerException (); 841 } 842 843 boolean result = false; 844 try { 845 factoryLock.acquireWrite(); 846 if (factories.remove(factory)) { 847 result = true; 848 clearCaches(); 849 } 850 } 851 finally { 852 factoryLock.releaseWrite(); 853 } 854 855 if (result) { 856 notifyChanged(); 857 } 858 return result; 859 } 860 861 865 public final void reset() { 866 try { 867 factoryLock.acquireWrite(); 868 reInitializeFactories(); 869 clearCaches(); 870 } 871 finally { 872 factoryLock.releaseWrite(); 873 } 874 notifyChanged(); 875 } 876 877 884 protected void reInitializeFactories() { 885 factories.clear(); 886 } 887 888 892 public boolean isDefault() { 893 return factories.size() == defaultSize; 894 } 895 896 900 protected void markDefault() { 901 defaultSize = factories.size(); 902 } 903 904 909 public Key createKey(String id) { 910 return id == null ? null : new Key(id); 911 } 912 913 920 protected void clearCaches() { 921 cacheref = null; 925 idref = null; 926 dnref = null; 927 } 928 929 935 protected void clearServiceCache() { 936 cacheref = null; 937 } 938 939 946 public static interface ServiceListener extends EventListener { 947 public void serviceChanged(ICUService service); 948 } 949 950 955 protected boolean acceptsListener(EventListener l) { 956 return l instanceof ServiceListener; 957 } 958 959 963 protected void notifyListener(EventListener l) { 964 ((ServiceListener)l).serviceChanged(this); 965 } 966 967 971 public String stats() { 972 ICURWLock.Stats stats = factoryLock.resetStats(); 973 if (stats != null) { 974 return stats.toString(); 975 } 976 return "no stats"; 977 } 978 979 982 public String getName() { 983 return name; 984 } 985 986 989 public String toString() { 990 return super.toString() + "{" + name + "}"; 991 } 992 } 993 | Popular Tags |