12ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* GENERATED SOURCE. DO NOT MODIFY. */ 2f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// © 2016 and later: Unicode, Inc. and others. 3f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License 42ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/** 52ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ******************************************************************************* 6f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * Copyright (C) 2001-2016, International Business Machines Corporation and 7f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * others. All Rights Reserved. 82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ******************************************************************************* 92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.impl; 112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.ArrayList; 132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Collections; 142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Comparator; 152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.EventListener; 162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.HashMap; 172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.HashSet; 182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Iterator; 192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.List; 202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.ListIterator; 212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Map; 222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Map.Entry; 232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Set; 242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.SortedMap; 252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.TreeMap; 26f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertimport java.util.concurrent.ConcurrentHashMap; 272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.ULocale; 292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.ULocale.Category; 302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/** 322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>A Service provides access to service objects that implement a 332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * particular service, e.g. transliterators. Users provide a String 342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * id (for example, a locale string) to the service, and get back an 352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * object for that id. Service objects can be any kind of object. 362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The service object is cached and returned for later queries, so 372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * generally it should not be mutable, or the caller should clone the 382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * object before modifying it.</p> 392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>Services 'canonicalize' the query id and use the canonical id to 412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * query for the service. The service also defines a mechanism to 422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 'fallback' the id multiple times. Clients can optionally request 432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the actual id that was matched by a query when they use an id to 442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * retrieve a service object.</p> 452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>Service objects are instantiated by Factory objects registered with 472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the service. The service queries each Factory in turn, from most recently 482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * registered to earliest registered, until one returns a service object. 492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If none responds with a service object, a fallback id is generated, 502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and the process repeats until a service object is returned or until 512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the id has no further fallbacks.</p> 522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>Factories can be dynamically registered and unregistered with the 542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * service. When registered, a Factory is installed at the head of 552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the factory list, and so gets 'first crack' at any keys or fallback 562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * keys. When unregistered, it is removed from the service and can no 572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * longer be located through it. Service objects generated by this 582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * factory and held by the client are unaffected.</p> 592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>ICUService uses Keys to query factories and perform 612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * fallback. The Key defines the canonical form of the id, and 622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * implements the fallback strategy. Custom Keys can be defined that 632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * parse complex IDs into components that Factories can more easily 642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * use. The Key can cache the results of this parsing to save 652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * repeated effort. ICUService provides convenience APIs that 662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * take Strings and generate default Keys for use in querying.</p> 672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>ICUService provides API to get the list of ids publicly 692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * supported by the service (although queries aren't restricted to 702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * this list). This list contains only 'simple' IDs, and not fully 712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * unique ids. Factories are associated with each simple ID and 722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the responsible factory can also return a human-readable localized 732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * version of the simple ID, for use in user interfaces. ICUService 742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * can also provide a sorted collection of the all the localized visible 752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * ids.</p> 762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>ICUService implements ICUNotifier, so that clients can register 782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * to receive notification when factories are added or removed from 792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the service. ICUService provides a default EventListener subinterface, 802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * ServiceListener, which can be registered with the service. When 812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the service changes, the ServiceListener's serviceChanged method 822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * is called, with the service as the only argument.</p> 832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>The ICUService API is both rich and generic, and it is expected 852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * that most implementations will statically 'wrap' ICUService to 862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * present a more appropriate API-- for example, to declare the type 872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * of the objects returned from get, to limit the factories that can 882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * be registered with the service, or to define their own listener 892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * interface with a custom callback method. They might also customize 902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * ICUService by overriding it, for example, to customize the Key and 912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * fallback strategy. ICULocaleService is a customized service that 922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * uses Locale names as ids and uses Keys that implement the standard 932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * resource bundle fallback strategy.<p> 94836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide Only a subset of ICU is exposed in Android 952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic class ICUService extends ICUNotifier { 972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Name used for debugging. 992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller protected final String name; 1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Constructor. 1042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public ICUService() { 1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller name = ""; 1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final boolean DEBUG = ICUDebug.enabled("service"); 1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Construct with a name (useful for debugging). 1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public ICUService(String name) { 1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.name = name; 1152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Access to factories is protected by a read-write lock. This is 1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * to allow multiple threads to read concurrently, but keep 1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * changes to the factory list atomic with respect to all readers. 1212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final ICURWLock factoryLock = new ICURWLock(); 1232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * All the factories registered with this service. 1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final List<Factory> factories = new ArrayList<Factory>(); 1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Record the default number of factories for this service. 1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Can be set by markDefault. 1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private int defaultSize = 0; 1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Keys are used to communicate with factories to generate an 1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * instance of the service. Keys define how ids are 1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * canonicalized, provide both a current id and a current 1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * descriptor to use in querying the cache and factories, and 1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * determine the fallback strategy.</p> 1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>Keys provide both a currentDescriptor and a currentID. 1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The descriptor contains an optional prefix, followed by '/' 1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and the currentID. Factories that handle complex keys, 1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * for example number format factories that generate multiple 1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * kinds of formatters for the same locale, use the descriptor 1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * to provide a fully unique identifier for the service object, 1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * while using the currentID (in this case, the locale string), 1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * as the visible IDs that can be localized. 1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p> The default implementation of Key has no fallbacks and 1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * has no custom descriptors.</p> 1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static class Key { 1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final String id; 1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Construct a key from an id. 1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Key(String id) { 1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.id = id; 1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return the original ID used to construct this key. 1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public final String id() { 1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return id; 1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return the canonical version of the original ID. This implementation 1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * returns the original ID unchanged. 1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String canonicalID() { 1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return id; 1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return the (canonical) current ID. This implementation 1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * returns the canonical ID. 1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String currentID() { 1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return canonicalID(); 1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return the current descriptor. This implementation returns 1892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the current ID. The current descriptor is used to fully 1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * identify an instance of the service in the cache. A 1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * factory may handle all descriptors for an ID, or just a 1922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * particular descriptor. The factory can either parse the 1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * descriptor or use custom API on the key in order to 1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * instantiate the service. 1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String currentDescriptor() { 1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return "/" + currentID(); 1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If the key has a fallback, modify the key and return true, 2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * otherwise return false. The current ID will change if there 2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * is a fallback. No currentIDs should be repeated, and fallback 2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * must eventually return false. This implmentation has no fallbacks 2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and always returns false. 2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean fallback() { 2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If a key created from id would eventually fallback to match the 2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * canonical ID of this key, return true. 2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean isFallbackOf(String idToCheck) { 2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return canonicalID().equals(idToCheck); 2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Factories generate the service objects maintained by the 2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * service. A factory generates a service object from a key, 2232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * updates id->factory mappings, and returns the display name for 2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * a supported id. 2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static interface Factory { 2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Create a service object from the key, if this factory 2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * supports the key. Otherwise, return null. 2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>If the factory supports the key, then it can call 2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the service's getKey(Key, String[], Factory) method 2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * passing itself as the factory to get the object that 2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the service would have created prior to the factory's 2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * registration with the service. This can change the 2372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * key, so any information required from the key should 2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * be extracted before making such a callback. 2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Object create(Key key, ICUService service); 2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Update the result IDs (not descriptors) to reflect the IDs 2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * this factory handles. This function and getDisplayName are 2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * used to support ICUService.getDisplayNames. Basically, the 2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * factory has to determine which IDs it will permit to be 2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * available, and of those, which it will provide localized 2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * display names for. In most cases this reflects the IDs that 2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the factory directly supports. 2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public void updateVisibleIDs(Map<String, Factory> result); 2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return the display name for this id in the provided locale. 2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This is an localized id, not a descriptor. If the id is 2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * not visible or not defined by the factory, return null. 2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If locale is null, return id unchanged. 2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String getDisplayName(String id, ULocale locale); 2602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * A default implementation of factory. This provides default 2642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * implementations for subclasses, and implements a singleton 2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * factory that matches a single id and returns a single 2662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * (possibly deferred-initialized) instance. This implements 2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * updateVisibleIDs to add a mapping from its ID to itself 2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * if visible is true, or to remove any existing mapping 2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * for its ID if visible is false. 2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static class SimpleFactory implements Factory { 2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller protected Object instance; 2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller protected String id; 2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller protected boolean visible; 2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Convenience constructor that calls SimpleFactory(Object, String, boolean) 2782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * with visible true. 2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public SimpleFactory(Object instance, String id) { 2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this(instance, id, true); 2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Construct a simple factory that maps a single id to a single 2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * service instance. If visible is true, the id will be visible. 2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Neither the instance nor the id can be null. 2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public SimpleFactory(Object instance, String id, boolean visible) { 2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (instance == null || id == null) { 2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalArgumentException("Instance or id is null"); 2922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.instance = instance; 2942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.id = id; 2952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.visible = visible; 2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return the service instance if the factory's id is equal to 3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the key's currentID. Service is ignored. 3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 302f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Object create(Key key, ICUService service) { 3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (id.equals(key.currentID())) { 3052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return instance; 3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If visible, adds a mapping from id -> this to the result, 3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * otherwise removes id from result. 3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 314f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 3152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public void updateVisibleIDs(Map<String, Factory> result) { 3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (visible) { 3172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result.put(id, this); 3182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 3192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result.remove(id); 3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If this.id equals id, returns id regardless of locale, 3252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * otherwise returns null. (This default implementation has 3262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * no localized id information.) 3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 328f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String getDisplayName(String identifier, ULocale locale) { 3302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return (visible && id.equals(identifier)) ? identifier : null; 3312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For debugging. 3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 336f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 3372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String toString() { 3382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller StringBuilder buf = new StringBuilder(super.toString()); 3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller buf.append(", id: "); 3402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller buf.append(id); 3412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller buf.append(", visible: "); 3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller buf.append(visible); 3432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return buf.toString(); 3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Convenience override for get(String, String[]). This uses 3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * createKey to create a key for the provided descriptor. 3502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Object get(String descriptor) { 3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getKey(createKey(descriptor), null); 3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Convenience override for get(Key, String[]). This uses 3572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * createKey to create a key from the provided descriptor. 3582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Object get(String descriptor, String[] actualReturn) { 3602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (descriptor == null) { 3612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new NullPointerException("descriptor must not be null"); 3622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getKey(createKey(descriptor), actualReturn); 3642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Convenience override for get(Key, String[]). 3682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Object getKey(Key key) { 3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getKey(key, null); 3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>Given a key, return a service object, and, if actualReturn 3752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * is not null, the descriptor with which it was found in the 3762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * first element of actualReturn. If no service object matches 3772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * this key, return null, and leave actualReturn unchanged.</p> 3782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 3792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>This queries the cache using the key's descriptor, and if no 3802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * object in the cache matches it, tries the key on each 3812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * registered factory, in order. If none generates a service 3822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * object for the key, repeats the process with each fallback of 3832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the key, until either one returns a service object, or the key 3842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * has no fallback.</p> 3852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 3862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>If key is null, just returns null.</p> 3872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Object getKey(Key key, String[] actualReturn) { 3892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getKey(key, actualReturn, null); 3902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // debugging 3932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Map hardRef; 3942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Object getKey(Key key, String[] actualReturn, Factory factory) { 3962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (factories.size() == 0) { 3972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return handleDefault(key, actualReturn); 3982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (DEBUG) System.out.println("Service: " + name + " key: " + key.canonicalID()); 4012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller CacheEntry result = null; 4032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (key != null) { 4042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller try { 4052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // The factory list can't be modified until we're done, 4062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // otherwise we might update the cache with an invalid result. 4072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // The cache has to stay in synch with the factory list. 4082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller factoryLock.acquireRead(); 4092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 410f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert Map<String, CacheEntry> cache = this.cache; // copy so we don't need to sync on this 4112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (cache == null) { 4122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (DEBUG) System.out.println("Service " + name + " cache was empty"); 4132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // synchronized since additions and queries on the cache must be atomic 4142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // they can be interleaved, though 415f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert cache = new ConcurrentHashMap<String, CacheEntry>(); 4162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String currentDescriptor = null; 4192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ArrayList<String> cacheDescriptorList = null; 4202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean putInCache = false; 4212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int NDebug = 0; 4232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int startIndex = 0; 4252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int limit = factories.size(); 4262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean cacheResult = true; 4272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (factory != null) { 4282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (int i = 0; i < limit; ++i) { 4292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (factory == factories.get(i)) { 4302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller startIndex = i + 1; 4312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 4322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (startIndex == 0) { 4352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalStateException("Factory " + factory + "not registered with service: " + this); 4362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller cacheResult = false; 4382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller outer: 4412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller do { 4422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller currentDescriptor = key.currentDescriptor(); 4432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (DEBUG) System.out.println(name + "[" + NDebug++ + "] looking for: " + currentDescriptor); 4442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result = cache.get(currentDescriptor); 4452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (result != null) { 4462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (DEBUG) System.out.println(name + " found with descriptor: " + currentDescriptor); 4472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break outer; 4482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 4492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (DEBUG) System.out.println("did not find: " + currentDescriptor + " in cache"); 4502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // first test of cache failed, so we'll have to update 4532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // the cache if we eventually succeed-- that is, if we're 4542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // going to update the cache at all. 4552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller putInCache = cacheResult; 4562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // int n = 0; 4582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int index = startIndex; 4592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller while (index < limit) { 4602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Factory f = factories.get(index++); 4612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (DEBUG) System.out.println("trying factory[" + (index-1) + "] " + f.toString()); 4622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Object service = f.create(key, this); 4632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (service != null) { 4642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result = new CacheEntry(currentDescriptor, service); 4652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (DEBUG) System.out.println(name + " factory supported: " + currentDescriptor + ", caching"); 4662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break outer; 4672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 4682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (DEBUG) System.out.println("factory did not support: " + currentDescriptor); 4692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // prepare to load the cache with all additional ids that 4732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // will resolve to result, assuming we'll succeed. We 4742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // don't want to keep querying on an id that's going to 4752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // fallback to the one that succeeded, we want to hit the 4762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // cache the first time next goaround. 4772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (cacheDescriptorList == null) { 4782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller cacheDescriptorList = new ArrayList<String>(5); 4792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller cacheDescriptorList.add(currentDescriptor); 4812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } while (key.fallback()); 4832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (result != null) { 4852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (putInCache) { 4862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (DEBUG) System.out.println("caching '" + result.actualDescriptor + "'"); 4872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller cache.put(result.actualDescriptor, result); 4882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (cacheDescriptorList != null) { 4892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (String desc : cacheDescriptorList) { 4902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (DEBUG) System.out.println(name + " adding descriptor: '" + desc + "' for actual: '" + result.actualDescriptor + "'"); 4912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller cache.put(desc, result); 4932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Atomic update. We held the read lock all this time 4962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // so we know our cache is consistent with the factory list. 4972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // We might stomp over a cache that some other thread 4982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // rebuilt, but that's the breaks. They're both good. 499f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert this.cache = cache; 5002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (actualReturn != null) { 5032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // strip null prefix 5042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (result.actualDescriptor.indexOf("/") == 0) { 5052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller actualReturn[0] = result.actualDescriptor.substring(1); 5062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 5072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller actualReturn[0] = result.actualDescriptor; 5082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (DEBUG) System.out.println("found in service: " + name); 5122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result.service; 5142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finally { 5172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller factoryLock.releaseRead(); 5182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (DEBUG) System.out.println("not found in service: " + name); 5222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return handleDefault(key, actualReturn); 5242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 525f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert private Map<String, CacheEntry> cache; 5262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Record the actual id for this service in the cache, so we can return it 5282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // even if we succeed later with a different id. 5292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final class CacheEntry { 5302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller final String actualDescriptor; 5312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller final Object service; 5322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller CacheEntry(String actualDescriptor, Object service) { 5332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.actualDescriptor = actualDescriptor; 5342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.service = service; 5352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Default handler for this service if no factory in the list 5412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * handled the key. 5422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller protected Object handleDefault(Key key, String[] actualIDReturn) { 5442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 5452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Convenience override for getVisibleIDs(String) that passes null 5492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * as the fallback, thus returning all visible IDs. 5502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Set<String> getVisibleIDs() { 5522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getVisibleIDs(null); 5532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>Return a snapshot of the visible IDs for this service. This 5572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * set will not change as Factories are added or removed, but the 5582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * supported ids will, so there is no guarantee that all and only 5592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the ids in the returned set are visible and supported by the 5602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * service in subsequent calls.</p> 5612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 5622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>matchID is passed to createKey to create a key. If the 5632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * key is not null, it is used to filter out ids that don't have 5642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the key as a fallback. 5652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Set<String> getVisibleIDs(String matchID) { 5672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Set<String> result = getVisibleIDMap().keySet(); 5682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Key fallbackKey = createKey(matchID); 5702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (fallbackKey != null) { 5722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Set<String> temp = new HashSet<String>(result.size()); 5732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (String id : result) { 5742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (fallbackKey.isFallbackOf(id)) { 5752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller temp.add(id); 5762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result = temp; 5792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 5812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return a map from visible ids to factories. 5852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private Map<String, Factory> getVisibleIDMap() { 587f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert synchronized (this) { // or idcache-only lock? 588f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (idcache == null) { 589f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert try { 590f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert factoryLock.acquireRead(); 591f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert Map<String, Factory> mutableMap = new HashMap<String, Factory>(); 592f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert ListIterator<Factory> lIter = factories.listIterator(factories.size()); 593f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert while (lIter.hasPrevious()) { 594f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert Factory f = lIter.previous(); 595f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert f.updateVisibleIDs(mutableMap); 5962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 597f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert this.idcache = Collections.unmodifiableMap(mutableMap); 598f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } finally { 599f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert factoryLock.releaseRead(); 6002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return idcache; 6042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 605f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert private Map<String, Factory> idcache; 6062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Convenience override for getDisplayName(String, ULocale) that 6092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * uses the current default locale. 6102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String getDisplayName(String id) { 6122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getDisplayName(id, ULocale.getDefault(Category.DISPLAY)); 6132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Given a visible id, return the display name in the requested locale. 6172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If there is no directly supported id corresponding to this id, return 6182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * null. 6192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String getDisplayName(String id, ULocale locale) { 6212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Map<String, Factory> m = getVisibleIDMap(); 6222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Factory f = m.get(id); 6232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (f != null) { 6242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return f.getDisplayName(id, locale); 6252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Key key = createKey(id); 6282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller while (key.fallback()) { 6292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller f = m.get(key.currentID()); 6302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (f != null) { 6312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return f.getDisplayName(id, locale); 6322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 634f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 6352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 6362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 639f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * Convenience override of getDisplayNames(ULocale, Comparator, String) that 6402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * uses the current default Locale as the locale, null as 6412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the comparator, and null for the matchID. 6422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public SortedMap<String, String> getDisplayNames() { 6442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ULocale locale = ULocale.getDefault(Category.DISPLAY); 6452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getDisplayNames(locale, null, null); 6462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Convenience override of getDisplayNames(ULocale, Comparator, String) that 6502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * uses null for the comparator, and null for the matchID. 6512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public SortedMap<String, String> getDisplayNames(ULocale locale) { 6532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getDisplayNames(locale, null, null); 6542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Convenience override of getDisplayNames(ULocale, Comparator, String) that 6582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * uses null for the matchID, thus returning all display names. 6592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public SortedMap<String, String> getDisplayNames(ULocale locale, Comparator<Object> com) { 6612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getDisplayNames(locale, com, null); 6622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Convenience override of getDisplayNames(ULocale, Comparator, String) that 6662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * uses null for the comparator. 6672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public SortedMap<String, String> getDisplayNames(ULocale locale, String matchID) { 6692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getDisplayNames(locale, null, matchID); 6702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return a snapshot of the mapping from display names to visible 6742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * IDs for this service. This set will not change as factories 6752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * are added or removed, but the supported ids will, so there is 6762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * no guarantee that all and only the ids in the returned map will 6772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * be visible and supported by the service in subsequent calls, 6782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * nor is there any guarantee that the current display names match 6792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * those in the set. The display names are sorted based on the 6802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * comparator provided. 6812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public SortedMap<String, String> getDisplayNames(ULocale locale, Comparator<Object> com, String matchID) { 6832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller SortedMap<String, String> dncache = null; 6842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller LocaleRef ref = dnref; 6852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (ref != null) { 6872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller dncache = ref.get(locale, com); 6882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller while (dncache == null) { 6912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller synchronized (this) { 6922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (ref == dnref || dnref == null) { 6932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller dncache = new TreeMap<String, String>(com); // sorted 694f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 6952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Map<String, Factory> m = getVisibleIDMap(); 6962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Iterator<Entry<String, Factory>> ei = m.entrySet().iterator(); 6972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller while (ei.hasNext()) { 6982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Entry<String, Factory> e = ei.next(); 6992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String id = e.getKey(); 7002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Factory f = e.getValue(); 7012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller dncache.put(f.getDisplayName(id, locale), id); 7022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller dncache = Collections.unmodifiableSortedMap(dncache); 7052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller dnref = new LocaleRef(dncache, locale, com); 7062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 7072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ref = dnref; 7082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller dncache = ref.get(locale, com); 7092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Key matchKey = createKey(matchID); 7142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (matchKey == null) { 7152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return dncache; 7162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller SortedMap<String, String> result = new TreeMap<String, String>(dncache); 7192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Iterator<Entry<String, String>> iter = result.entrySet().iterator(); 7202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller while (iter.hasNext()) { 7212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Entry<String, String> e = iter.next(); 7222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!matchKey.isFallbackOf(e.getValue())) { 7232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller iter.remove(); 7242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 7272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // we define a class so we get atomic simultaneous access to the 7302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // locale, comparator, and corresponding map. 7312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static class LocaleRef { 7322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final ULocale locale; 733f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert private SortedMap<String, String> dnCache; 7342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private Comparator<Object> com; 7352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller LocaleRef(SortedMap<String, String> dnCache, ULocale locale, Comparator<Object> com) { 7372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.locale = locale; 7382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.com = com; 739f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert this.dnCache = dnCache; 7402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller SortedMap<String, String> get(ULocale loc, Comparator<Object> comp) { 744f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert SortedMap<String, String> m = dnCache; 7452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (m != null && 7462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.locale.equals(loc) && 7472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller (this.com == comp || (this.com != null && this.com.equals(comp)))) { 7482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return m; 7502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 7522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private LocaleRef dnref; 7552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 7572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return a snapshot of the currently registered factories. There 7582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * is no guarantee that the list will still match the current 7592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * factory list of the service subsequent to this call. 7602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 7612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public final List<Factory> factories() { 7622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller try { 7632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller factoryLock.acquireRead(); 7642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return new ArrayList<Factory>(factories); 7652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finally{ 7672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller factoryLock.releaseRead(); 7682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 7722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * A convenience override of registerObject(Object, String, boolean) 7732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * that defaults visible to true. 7742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 7752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Factory registerObject(Object obj, String id) { 7762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return registerObject(obj, id, true); 7772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 7802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Register an object with the provided id. The id will be 7812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * canonicalized. The canonicalized ID will be returned by 7822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * getVisibleIDs if visible is true. 7832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 7842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Factory registerObject(Object obj, String id, boolean visible) { 7852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String canonicalID = createKey(id).canonicalID(); 7862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return registerFactory(new SimpleFactory(obj, canonicalID, visible)); 7872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 7902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Register a Factory. Returns the factory if the service accepts 7912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the factory, otherwise returns null. The default implementation 7922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * accepts all factories. 7932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 7942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public final Factory registerFactory(Factory factory) { 7952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (factory == null) { 7962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new NullPointerException(); 7972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller try { 7992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller factoryLock.acquireWrite(); 8002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller factories.add(0, factory); 8012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller clearCaches(); 8022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finally { 8042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller factoryLock.releaseWrite(); 8052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller notifyChanged(); 8072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return factory; 8082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Unregister a factory. The first matching registered factory will 8122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * be removed from the list. Returns true if a matching factory was 8132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * removed. 8142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public final boolean unregisterFactory(Factory factory) { 8162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (factory == null) { 8172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new NullPointerException(); 8182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean result = false; 8212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller try { 8222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller factoryLock.acquireWrite(); 8232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (factories.remove(factory)) { 8242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result = true; 8252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller clearCaches(); 8262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finally { 8292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller factoryLock.releaseWrite(); 8302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (result) { 8332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller notifyChanged(); 8342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 8362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Reset the service to the default factories. The factory 8402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * lock is acquired and then reInitializeFactories is called. 8412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public final void reset() { 8432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller try { 8442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller factoryLock.acquireWrite(); 8452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller reInitializeFactories(); 8462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller clearCaches(); 8472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller finally { 8492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller factoryLock.releaseWrite(); 8502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller notifyChanged(); 8522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Reinitialize the factory list to its default state. By default 8562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * this clears the list. Subclasses can override to provide other 8572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * default initialization of the factory list. Subclasses must 8582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * not call this method directly, as it must only be called while 8592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * holding write access to the factory list. 8602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller protected void reInitializeFactories() { 8622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller factories.clear(); 8632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return true if the service is in its default state. The default 8672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * implementation returns true if there are no factories registered. 8682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean isDefault() { 8702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return factories.size() == defaultSize; 8712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Set the default size to the current number of registered factories. 8752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Used by subclasses to customize the behavior of isDefault. 8762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller protected void markDefault() { 8782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller defaultSize = factories.size(); 8792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Create a key from an id. This creates a Key instance. 8832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Subclasses can override to define more useful keys appropriate 8842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * to the factories they accept. If id is null, returns null. 8852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Key createKey(String id) { 8872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return id == null ? null : new Key(id); 8882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Clear caches maintained by this service. Subclasses can 8922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * override if they implement additional that need to be cleared 8932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * when the service changes. Subclasses should generally not call 8942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * this method directly, as it must only be called while 8952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * synchronized on this. 8962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller protected void clearCaches() { 8982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // we don't synchronize on these because methods that use them 8992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // copy before use, and check for changes if they modify the 9002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // caches. 901f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert cache = null; 902f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert idcache = null; 9032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller dnref = null; 9042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Clears only the service cache. 9082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This can be called by subclasses when a change affects the service 9092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * cache but not the id caches, e.g., when the default locale changes 9102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the resolution of ids changes, but not the visible ids themselves. 9112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 9122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller protected void clearServiceCache() { 913f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert cache = null; 9142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * ServiceListener is the listener that ICUService provides by default. 9182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * ICUService will notifiy this listener when factories are added to 9192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * or removed from the service. Subclasses can provide 9202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * different listener interfaces that extend EventListener, and modify 9212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * acceptsListener and notifyListener as appropriate. 9222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 9232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static interface ServiceListener extends EventListener { 9242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public void serviceChanged(ICUService service); 9252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return true if the listener is accepted; by default this 9292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * requires a ServiceListener. Subclasses can override to accept 9302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * different listeners. 9312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 932f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 9332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller protected boolean acceptsListener(EventListener l) { 9342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return l instanceof ServiceListener; 9352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Notify the listener, which by default is a ServiceListener. 9392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Subclasses can override to use a different listener. 9402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 941f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 9422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller protected void notifyListener(EventListener l) { 9432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ((ServiceListener)l).serviceChanged(this); 9442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * When the statistics for this service is already enabled, 9482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * return the log and resets he statistics. 9492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * When the statistics is not enabled, this method enable 9502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the statistics. Used for debugging purposes. 9512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 9522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String stats() { 9532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ICURWLock.Stats stats = factoryLock.resetStats(); 9542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (stats != null) { 9552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return stats.toString(); 9562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return "no stats"; 9582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return the name of this service. This will be the empty string if none was assigned. 9622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 9632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String getName() { 9642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return name; 9652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Returns the result of super.toString, appending the name in curly braces. 9692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 970f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 9712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String toString() { 9722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return super.toString() + "{" + name + "}"; 9732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller} 975