ICU-2203 registration for calendar, breakiterator

X-SVN-Rev: 9948
This commit is contained in:
Doug Felt 2002-10-02 20:20:26 +00:00
parent c9cf5f3592
commit a90995824f
18 changed files with 1116 additions and 702 deletions

View file

@ -5,15 +5,17 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/dev/test/calendar/CalendarRegression.java,v $
* $Date: 2002/08/13 21:53:38 $
* $Revision: 1.12 $
* $Date: 2002/10/02 20:20:26 $
* $Revision: 1.13 $
*
*******************************************************************************
*/
package com.ibm.icu.dev.test.calendar;
import com.ibm.icu.util.*;
import java.util.Date;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;
import com.ibm.icu.lang.*;
import com.ibm.icu.text.*;
@ -705,6 +707,7 @@ public class CalendarRegression extends com.ibm.icu.dev.test.TestFmwk {
public void Test4106136() {
Locale saveLocale = Locale.getDefault();
String[] names = { "Calendar", "DateFormat", "NumberFormat" };
try {
Locale[] locales = { Locale.CHINESE, Locale.CHINA };
for (int i=0; i<locales.length; ++i) {
@ -716,7 +719,7 @@ public class CalendarRegression extends com.ibm.icu.dev.test.TestFmwk {
};
for (int j=0; j<n.length; ++j) {
if (n[j] == 0)
errln("Fail: No locales for " + locales[i]);
errln("Fail: " + names[j] + " has no locales for " + locales[i]);
}
}
}
@ -1834,6 +1837,49 @@ public class CalendarRegression extends com.ibm.icu.dev.test.TestFmwk {
TimeZone.setDefault(zone);
}
}
public void TestRegistration() {
Set names = Calendar.getCalendarFactoryNames();
TimeZone tz = TimeZone.getDefault();
Locale loc = Locale.getDefault();
Iterator iter = names.iterator();
while (iter.hasNext()) {
String name = (String)iter.next();
logln("Testing factory: " + name);
Calendar cal = Calendar.getInstance(tz, loc, name);
logln("Calendar class: " + cal.getClass());
DateFormat fmt = cal.getDateTimeFormat(DateFormat.LONG, DateFormat.LONG, loc);
logln("Date: " + fmt.format(cal.getTime()));
}
// register new default for our locale
logln("\nTesting registration");
loc = new Locale("en", "US");
Object key = Calendar.register(JapaneseCalendar.factory(), loc, true);
loc = new Locale("en", "US", "TEST");
Calendar cal = Calendar.getInstance(loc);
logln("Calendar class: " + cal.getClass());
DateFormat fmt = cal.getDateTimeFormat(DateFormat.LONG, DateFormat.LONG, loc);
logln("Date: " + fmt.format(cal.getTime()));
// force to use other default anyway
logln("\nOverride registration");
cal = Calendar.getInstance(tz, loc, "Gregorian");
fmt = cal.getDateTimeFormat(DateFormat.LONG, DateFormat.LONG, loc);
logln("Date: " + fmt.format(cal.getTime()));
// unregister default
logln("\nUnregistration");
logln("Unregister returned: " + Calendar.unregister(key));
cal = Calendar.getInstance(tz, loc, "Gregorian");
fmt = cal.getDateTimeFormat(DateFormat.LONG, DateFormat.LONG, loc);
logln("Date: " + fmt.format(cal.getTime()));
}
}
//eof

View file

@ -5,8 +5,8 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/dev/test/util/ICUServiceTest.java,v $
* $Date: 2002/09/14 21:36:30 $
* $Revision: 1.5 $
* $Date: 2002/10/02 20:20:25 $
* $Revision: 1.6 $
*
*******************************************************************************
*/
@ -24,10 +24,11 @@ import com.ibm.icu.impl.LocaleUtility;
import com.ibm.icu.impl.ICULocaleData;
import com.ibm.icu.impl.ICULocaleService;
import com.ibm.icu.impl.ICULocaleService.LocaleKey;
import com.ibm.icu.impl.ICULocaleService.MultipleKeyFactory;
import com.ibm.icu.impl.ICULocaleService.LocaleKeyFactory;
import com.ibm.icu.impl.ICULocaleService.ICUResourceBundleFactory;
import java.util.Arrays;
import java.util.Collections;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
@ -69,7 +70,7 @@ public class ICUServiceTest extends TestFmwk
// use locale keys
static final class TestService extends ICUService {
protected Key createKey(String id) {
public Key createKey(String id) {
return LocaleKey.createWithCanonicalFallback(id, null); // no fallback locale
}
}
@ -203,7 +204,7 @@ public class ICUServiceTest extends TestFmwk
"en_US_SURFER_GAL",
"en_US_SURFER_DUDE"
};
service.registerFactory(new TestMultipleFactory(xids));
service.registerFactory(new TestLocaleKeyFactory(xids));
}
// iterate over the visual ids returned by the multiple factory
@ -246,7 +247,7 @@ public class ICUServiceTest extends TestFmwk
String[] xids = {
"en_US_SURFER_GAL", "en_US_SILICON", "en_US_SILICON_GEEK", "en_US"
};
service.registerFactory(new TestMultipleFactory(xids, "Rad dude"));
service.registerFactory(new TestLocaleKeyFactory(xids, "Rad dude"));
}
// this time, we have seven display names (we replaced surfer gal)
@ -332,10 +333,9 @@ public class ICUServiceTest extends TestFmwk
// resource bundle factory.
service.reset();
service.registerFactory(new ICUResourceBundleFactory("Countries;Languages", true));
service.registerFactory(new ICUResourceBundleFactory());
// list all of the resources that really define Countries;Languages
// this takes a long time to build the visible id list
// list all of the resources
{
Set xids = service.getVisibleIDs();
StringBuffer buf = new StringBuffer("{");
@ -453,16 +453,18 @@ public class ICUServiceTest extends TestFmwk
}
static class TestMultipleFactory extends MultipleKeyFactory {
protected final String[] ids;
static class TestLocaleKeyFactory extends LocaleKeyFactory {
protected final Set ids;
protected final String factoryID;
public TestMultipleFactory(String[] ids) {
public TestLocaleKeyFactory(String[] ids) {
this(ids, "");
}
public TestMultipleFactory(String[] ids, String factoryID) {
this.ids = (String[])ids.clone();
public TestLocaleKeyFactory(String[] ids, String factoryID) {
super(VISIBLE_COVERS);
this.ids = Collections.unmodifiableSet(new HashSet(Arrays.asList(ids)));
if (factoryID == null || factoryID.length() == 0) {
this.factoryID = "";
@ -471,21 +473,12 @@ public class ICUServiceTest extends TestFmwk
}
}
protected Object handleCreate(Key key) {
for (int i = 0; i < ids.length; ++i) {
if (key.currentID().equalsIgnoreCase(ids[i])) {
return factoryID + key.canonicalID();
}
}
return null;
protected Object handleCreate(Locale loc, int kind) {
return factoryID + loc.toString();
}
protected Set handleGetSupportedIDs() {
return new HashSet(Arrays.asList(ids));
}
protected String handleGetDisplayName(String id, Locale locale) {
return factoryID + LocaleUtility.getLocaleFromName(id).getDisplayName(locale);
protected Set getSupportedIDs() {
return ids;
}
}
@ -535,27 +528,26 @@ public class ICUServiceTest extends TestFmwk
}
static class CalifornioLanguageFactory extends ICUResourceBundleFactory {
CalifornioLanguageFactory() {
super("Countries;Languages", true);
}
private static String californio = "en_US_CA";
private static String valley = californio + "_VALLEY";
private static String surfer = californio + "_SURFER";
private static String geek = californio + "_GEEK";
public Set handleGetSupportedIDs() {
Set result = super.handleGetSupportedIDs();
private static Set supportedIDs;
static {
HashSet result = new HashSet();
result.addAll(ICULocaleData.getAvailableLocaleNameSet());
result.add(californio);
result.add(valley);
result.add(surfer);
result.add(geek);
supportedIDs = Collections.unmodifiableSet(result);
}
return result;
public Set getSupportedIDs() {
return supportedIDs;
}
protected String handleGetDisplayName(String id, Locale locale) {
public String getDisplayName(String id, Locale locale) {
String prefix = "";
String suffix = "";
String ls = locale.toString();
@ -581,7 +573,7 @@ public class ICUServiceTest extends TestFmwk
suffix = "No Habla Englais";
}
} else {
suffix = super.handleGetDisplayName(id, locale);
suffix = super.getDisplayName(id, locale);
}
return prefix + suffix;
@ -624,7 +616,6 @@ public class ICUServiceTest extends TestFmwk
public void errln(String msg) {
System.out.println(msg);
(new String[0])[1] = "foo";
}
// misc coverage tests
@ -730,26 +721,21 @@ public class ICUServiceTest extends TestFmwk
// lkey = LocaleKey.create(null, null);
LocaleKey lkey = LocaleKey.createWithCanonicalFallback("en_US", "ja_JP");
// MultipleKeyFactory
MultipleKeyFactory mkf = new MKFSubclass(false);
logln("obj: " + mkf.create(lkey));
logln(mkf.getDisplayName("foo", null));
logln(mkf.getDisplayName("bar", null));
mkf.updateVisibleIDs(new HashMap());
// LocaleKeyFactory
LocaleKeyFactory lkf = new LKFSubclass(false);
logln("obj: " + lkf.create(lkey));
logln(lkf.getDisplayName("foo", null));
logln(lkf.getDisplayName("bar", null));
lkf.updateVisibleIDs(new HashMap());
MultipleKeyFactory invisibleMKF = new MKFSubclass(false);
logln("obj: " + invisibleMKF.create(lkey));
logln(invisibleMKF.getDisplayName("foo", null));
logln(invisibleMKF.getDisplayName("bar", null));
invisibleMKF.updateVisibleIDs(new HashMap());
LocaleKeyFactory invisibleLKF = new LKFSubclass(false);
logln("obj: " + invisibleLKF.create(lkey));
logln(invisibleLKF.getDisplayName("foo", null));
logln(invisibleLKF.getDisplayName("bar", null));
invisibleLKF.updateVisibleIDs(new HashMap());
// ResourceBundleFactory
ICUResourceBundleFactory rbf = new ICUResourceBundleFactory(true);
logln("RB: " + rbf.create(lkey));
// LocaleKey nokey = LocaleKey.create(null, null);
// logln("RB: " + rbf.create(nokey));
rbf = new ICUResourceBundleFactory("foobar", true);
ICUResourceBundleFactory rbf = new ICUResourceBundleFactory();
logln("RB: " + rbf.create(lkey));
// ICUNotifier
@ -813,17 +799,17 @@ public class ICUServiceTest extends TestFmwk
}
}
static class MKFSubclass extends MultipleKeyFactory {
MKFSubclass(boolean visible) {
super(visible);
static class LKFSubclass extends LocaleKeyFactory {
LKFSubclass(boolean visible) {
super(visible ? VISIBLE : INVISIBLE);
}
public Object handleCreate(Key key) {
return null;
}
public Set handleGetSupportedIDs() {
return null;
protected Set getSupportedIDs() {
return Collections.EMPTY_SET;
}
}
}

View file

@ -5,8 +5,8 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/dev/test/util/ICUServiceThreadTest.java,v $
* $Date: 2002/08/13 22:10:20 $
* $Revision: 1.4 $
* $Date: 2002/10/02 20:20:25 $
* $Revision: 1.5 $
*
*******************************************************************************
*/
@ -22,7 +22,6 @@ import com.ibm.icu.impl.LocaleUtility;
import com.ibm.icu.impl.ICULocaleData;
import com.ibm.icu.impl.ICULocaleService;
import com.ibm.icu.impl.ICULocaleService.LocaleKey;
import com.ibm.icu.impl.ICULocaleService.MultipleKeyFactory;
import com.ibm.icu.impl.ICULocaleService.ICUResourceBundleFactory;
import java.util.Arrays;
import java.util.ArrayList;

View file

@ -4,10 +4,16 @@
package com.ibm.icu.impl;
import java.lang.ref.SoftReference;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Provides information about and access to resource bundles in the
@ -23,6 +29,9 @@ public class ICULocaleData {
/**
* Returns a list of the installed locales.
*
* The following note by Rich is obsolete, see below. -- dlf 01 Oct. 2002
* -----
* @param key A resource tag. Currently, this parameter is ignored. The obvious
* intent, however, is for getAvailableLocales() to return a list of only those
* locales that contain a resource with the specified resource tag.
@ -35,7 +44,7 @@ public class ICULocaleData {
* inheriting one from another locale. Thus, if fr and fr_CA uniquely define
* NumberFormat data, but fr_BE doesn't, the user wouldn't see "French (Belgium)" in
* the list and would go for "French (default)" instead. Of course, this means
* "English (United States)" would not be in the list, since it is the default locale.
* "Engish (United States)" would not be in the list, since it is the default locale.
* This might be okay, but might be confusing to some users.
*
* <p>In addition, the other functions that call getAvailableLocales() don't currently
@ -44,28 +53,97 @@ public class ICULocaleData {
*
* <p>We recommend that someone take some careful consideration of these issues before
* modifying this function to pay attention to the "key" parameter. --rtg 1/26/98
* -----
*
* Return a list of the locales supported by a collection of resource bundles.
* All ICULocaleData-based services that use a particular resource bundle support
* all the locales from that bundle. If support for a particular service is spotty,
* a different bundle prefix should be used for that service.
* @param bundlePrefix the prefix of the resource bundles to use.
*/
public static Locale[] getAvailableLocales(String key) {
// ignore key, just return all locales
return getAvailableLocales();
public static Locale[] getAvailableLocales(String bundlePrefix) {
return (Locale[])getAvailEntry(bundlePrefix).getLocaleList().clone();
}
/**
* Return an array of all the locales for which we have resource information.
* Convenience method that returns a list of all the avilable LOCALE_ELEMENTS locales.
*/
public static Locale[] getAvailableLocales() {
// creating the locale list is expensive, so be careful to do it
// only once
if (localeList == null) {
synchronized(ICULocaleData.class) {
if (localeList == null) {
localeList = createLocaleList();
}
return getAvailableLocales(LOCALE_ELEMENTS);
}
/**
* Return a set of the locale names supported by a collection of resource bundles.
* @param bundlePrefix the prefix of the resource bundles to use.
*/
public static Set getAvailableLocaleNameSet(String bundlePrefix) {
return getAvailEntry(bundlePrefix).getLocaleNameSet();
}
/**
* Return a set of the locale names supported by a collection of resource bundles.
* @param bundlePrefix the prefix of the resource bundles to use.
*/
public static Set getAvailableLocaleNameSet() {
return getAvailableLocaleNameSet(LOCALE_ELEMENTS);
}
/**
* Holds the prefix, and lazily creates the Locale[] list or the locale name Set as needed.
*/
private static final class AvailEntry {
private String prefix;
private Locale[] locales;
private Set nameSet;
AvailEntry(String prefix) {
this.prefix = prefix;
}
Locale[] getLocaleList() {
if (locales == null) {
locales = createLocaleList(prefix);
}
return locales;
}
Set getLocaleNameSet() {
if (nameSet == null) {
nameSet = createLocaleNameSet(prefix);
}
return nameSet;
}
}
/**
* Stores the locale information in a cache accessed by key (bundle prefix). The
* cached objects are AvailEntries. The cache is held by a SoftReference
* so it can be GC'd.
*/
private static AvailEntry getAvailEntry(String key) {
AvailEntry ae = null;
Map lcache = null;
if (lcacheref != null) {
lcache = (Map)lcacheref.get();
if (lcache != null) {
ae = (AvailEntry)lcache.get(key);
}
}
return (Locale[])localeList.clone();
if (ae == null) {
ae = new AvailEntry(key);
if (lcache == null) {
lcache = new HashMap();
lcache.put(key, ae);
lcacheref = new SoftReference(lcache);
} else {
lcache.put(key, ae);
}
}
return ae;
}
private static SoftReference lcacheref;
/**
* The default name for resources containing ICU locale data.
@ -218,10 +296,33 @@ public class ICULocaleData {
// ========== privates ==========
private static Locale[] createLocaleList() {
private static Set createLocaleNameSet(String bundleName) {
try {
ResourceBundle index = getLocaleElements(LocaleUtility.getLocaleFromName("index"));
ResourceBundle index = getResourceBundle(bundleName, "index");
String[] localeNames = index.getStringArray("InstalledLocales");
// barf gag choke spit hack...
// since java's Locale 'fixes' the locale string for some locales,
// we have to fix our names to match, otherwise the Locale[] list
// won't match the locale name set. What were they thinking?!?
for (int i = 0; i < localeNames.length; ++i) {
localeNames[i] = LocaleUtility.getLocaleFromName(localeNames[i]).toString();
}
HashSet set = new HashSet();
set.addAll(Arrays.asList(localeNames));
return Collections.unmodifiableSet(set);
}
catch (MissingResourceException e) {
System.out.println("couldn't find index for bundleName: " + bundleName);
Thread.dumpStack();
}
return Collections.EMPTY_SET;
}
private static Locale[] createLocaleList(String bundleName) {
try {
ResourceBundle index = getResourceBundle(bundleName, "index");
String[] localeNames = index.getStringArray("InstalledLocales");
Locale[] locales = new Locale[localeNames.length];
for (int i = 0; i < localeNames.length; ++i) {
@ -230,8 +331,9 @@ public class ICULocaleData {
return locales;
}
catch (MissingResourceException e) {
System.out.println("couldn't find index for bundleName: " + bundleName);
Thread.dumpStack();
}
return new Locale[0];
}
}

View file

@ -5,8 +5,8 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/impl/ICULocaleService.java,v $
* $Date: 2002/09/14 21:36:30 $
* $Revision: 1.7 $
* $Date: 2002/10/02 20:20:21 $
* $Revision: 1.8 $
*
*******************************************************************************
*/
@ -14,6 +14,7 @@ package com.ibm.icu.impl;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -29,7 +30,7 @@ public class ICULocaleService extends ICUService {
private String fallbackLocaleName;
/**
* Construct an ICULocaleService. This uses the current default locale as a fallback.
* Construct an ICULocaleService.
*/
public ICULocaleService() {
}
@ -42,21 +43,44 @@ public class ICULocaleService extends ICUService {
}
/**
* Convenience override for callers using locales.
* Convenience override for callers using locales. This calls
* get(Locale, int, Locale[]) with KIND_ANY for kind and null for
* actualReturn.
*/
public Object get(Locale locale) {
return get(locale, null);
return get(locale, LocaleKey.KIND_ANY, null);
}
/**
* Convenience override for callers using locales.
* Convenience override for callers using locales. This calls
* get(Locale, int, Locale[]) with a null actualReturn.
*/
public Object get(Locale locale, int kind) {
return get(locale, kind, null);
}
/**
* Convenience override for callers using locales. This calls
* get(Locale, String, Locale[]) with a null kind.
*/
public Object get(Locale locale, Locale[] actualReturn) {
return get(locale, LocaleKey.KIND_ANY, actualReturn);
}
/**
* Convenience override for callers using locales. This uses
* createKey(Locale.toString(), kind) to create a key, calls getKey, and then
* if actualReturn is not null, returns the actualResult from
* getKey into a Locale.
*/
public Object get(Locale locale, int kind, Locale[] actualReturn) {
Key key = createKey(locale.toString(), kind);
if (actualReturn == null) {
return get(locale.toString());
return getKey(key);
}
String[] temp = new String[1];
Object result = get(locale.toString(), temp);
Object result = getKey(key, temp);
if (result != null) {
actualReturn[0] = LocaleUtility.getLocaleFromName(temp[0]);
}
@ -64,22 +88,35 @@ public class ICULocaleService extends ICUService {
}
/**
* Convenience override for callers using locales.
* Convenience override for callers using locales. This calls
* registerObject(Object, Locale, int kind, int coverage)
* passing KIND_ANY for the kind, and VISIBLE for the coverage.
*/
public Factory registerObject(Object obj, Locale locale) {
return registerObject(obj, locale, true);
return registerObject(obj, locale, LocaleKey.KIND_ANY, LocaleKeyFactory.VISIBLE);
}
/**
* Convenience override for callers using locales.
* Convenience function for callers using locales. This calls
* registerObject(Object, Locale, int kind, int coverage)
* passing VISIBLE for the coverage.
*/
public Factory registerObject(Object obj, Locale locale, boolean visible) {
return registerObject(obj, locale.toString(), visible);
public Factory registerObject(Object obj, Locale locale, int kind) {
return registerObject(obj, locale, kind, LocaleKeyFactory.VISIBLE);
}
/**
* Convenience method for callers using locales. This is the
* current typical API for this operation, though perhaps it should change.
* Convenience function for callers using locales. This instantiates
* a SimpleLocaleKeyFactory, and registers the factory.
*/
public Factory registerObject(Object obj, Locale locale, int kind, int coverage) {
Factory factory = new SimpleLocaleKeyFactory(obj, locale, kind, coverage);
return registerFactory(factory);
}
/**
* Convenience method for callers using locales. This returns the standard
* Locale list, built from the Set of visible ids.
*/
public Locale[] getAvailableLocales() {
Set visIDs = getVisibleIDs();
@ -106,24 +143,26 @@ public class ICULocaleService extends ICUService {
* is in upper case, with no trailing underscores.</p>
*/
public static class LocaleKey extends ICUService.Key {
private String prefix;
private int kind;
private String primaryID;
private String fallbackID;
private String currentID;
public static final int KIND_ANY = -1;
/**
* Create a LocaleKey with canonical primary and fallback IDs.
*/
public static LocaleKey createWithCanonicalFallback(String primaryID, String canonicalFallbackID) {
return createWithCanonicalFallback(primaryID, canonicalFallbackID, null);
return createWithCanonicalFallback(primaryID, canonicalFallbackID, KIND_ANY);
}
/**
* Create a LocaleKey with canonical primary and fallback IDs.
*/
public static LocaleKey createWithCanonicalFallback(String primaryID, String canonicalFallbackID, String prefix) {
public static LocaleKey createWithCanonicalFallback(String primaryID, String canonicalFallbackID, int kind) {
String canonicalPrimaryID = LocaleUtility.canonicalLocaleString(primaryID);
return new LocaleKey(primaryID, canonicalPrimaryID, canonicalFallbackID, prefix);
return new LocaleKey(primaryID, canonicalPrimaryID, canonicalFallbackID, kind);
}
/**
@ -132,10 +171,10 @@ public class ICULocaleService extends ICUService {
* fallbackID is the current default locale's string in
* canonical form.
*/
protected LocaleKey(String primaryID, String canonicalPrimaryID, String canonicalFallbackID, String prefix) {
protected LocaleKey(String primaryID, String canonicalPrimaryID, String canonicalFallbackID, int kind) {
super(primaryID);
this.prefix = prefix;
this.kind = kind;
if (canonicalPrimaryID == null) {
this.primaryID = "";
@ -156,10 +195,17 @@ public class ICULocaleService extends ICUService {
}
/**
* Return the prefix, or null if none was defined.
* Return the prefix associated with the kind, or null if the kind is KIND_ANY.
*/
public String prefix() {
return prefix;
return kind == KIND_ANY ? null : Integer.toString(kind());
}
/**
* Return the kind code associated with this key.
*/
public int kind() {
return kind;
}
/**
@ -181,8 +227,11 @@ public class ICULocaleService extends ICUService {
*/
public String currentDescriptor() {
String result = currentID();
if (result != null && prefix != null) {
result = prefix + "/" + result;
if (result != null) {
result = "/" + result;
if (kind != KIND_ANY) {
result = prefix() + result;
}
}
return result;
}
@ -227,419 +276,299 @@ public class ICULocaleService extends ICUService {
}
/**
* This is a factory that handles multiple keys, and records
* information about the keys it handles or doesn't handle. This
* allows it to quickly filter subsequent queries on keys it has
* seen before. Subclasses implement handleCreate instead of
* create. Before updateVisibleIDs is called, it keeps track of
* keys that it doesn't handle. If its ids are visible, once
* updateVisibleIDs is called, it builds a set of all the keys it
* does handle and keeps track of the keys it does handle.
* A subclass of Factory that uses LocaleKeys, and is able to
* 'cover' more specific locales with more general locales that it
* supports.
*
* <p>Covers may be any of the values VISIBLE,
* INVISIBLE, VISIBLE_COVERS, INVISIBLE_COVERS, or
* VISIBLE_COVERS_REMOVE.
*
* <p>'Visible' indicates that the specific locale(s) supported by
* the factory are registered in getSupportedIDs, 'Invisible'
* indicates that they are not. 'Covers' indicates that the
* factory preempts previously-registered factories from handling
* more specific locales (for one or more kinds); if visible, these
* locales remain in visible ids, otherwise they are removed.
* 'Visible covers remove' leaves the 'original' locale visible,
* but makes the covered sublocales invisible, like
* invisible_covers.
*
* <p>Localization of visible ids (covered or primary) is handled
* by the covering factory, regardless of kind.
*
* <p><b>Example 1:</b> Factory A supports en_US with coverage
* VISIBLE_COVERS. Previously-registered factory B supports
* en_US_CALIFORNIA. getVisibleIDs will return both en_US and
* en_US_CALIFORNIA, Factory A will handle both of them and
* localize the ids for both of these.
*
* <p><b>Example 2:</b> Factory A supports word/en_US with
* coverage VISIBLE_COVERS_REMOVE. Previously-registered factory
* B supports /en_US_CALIFORNIA (all kinds). getVisibleIDs will
* return only en_US and not en_US_CALIFORNIA, Factory A will
* handle word/en_US and word/en_US_CALIFORNIA, and also localize
* the id en_US. Factory B will handle other kinds of requests
* under en_US_CALIFORNIA.
*/
public static abstract class MultipleKeyFactory implements ICUService.Factory {
protected final boolean visible;
private SoftReference cacheref;
private static final class CacheInfo {
final Set cache;
final boolean included;
CacheInfo() {
this.cache = new HashSet();
this.included = false;
}
CacheInfo(Set cache) {
this.cache = cache;
this.included = true;
}
/**
* Return true if we're known to support id, or not known to not support id.
*/
boolean tryCreate(String id) {
boolean result = cache.contains(id) == included;
return result;
}
/**
* Update information about whether we support this id. Since if we are storing
* information on included ids, we already know all of them, we only need to
* update if we're storing information on ids we don't support and we don't
* support the id (the result is null).
*/
void addCreate(String id, Object result) {
if (!included && result == null) {
cache.add(id);
}
}
}
/**
* Convenience overload of MultipleKeyFactory(boolean) that defaults
* visible to true.
*/
public MultipleKeyFactory() {
this(true);
}
/**
* Constructs a MultipleKeyFactory whose ids are visible iff visible is true.
*/
public MultipleKeyFactory(boolean visible) {
this.visible = visible;
}
/**
* Get the cache of IDs. These are either the ids that we know we
* don't understand, if included is false, or the entire set of ids
* we do know we understand, if included is true. If the cache has
* been flushed, included is false.
*/
private CacheInfo getCache() {
CacheInfo result = null;
if (cacheref != null) {
result = (CacheInfo)cacheref.get();
}
if (result == null) {
result = new CacheInfo();
cacheref = new SoftReference(result);
}
return result;
}
/**
* Get the cache of IDs we understand.
*/
protected Set getSupportedIDs() {
CacheInfo ci = getCache();
Set result = ci.cache;
if (!ci.included) {
result = handleGetSupportedIDs();
cacheref = new SoftReference(new CacheInfo(result));
}
return result;
}
public Object create(Key key) {
Object result = null;
String id = key.currentID();
CacheInfo ci = getCache();
if (ci.tryCreate(id)) {
result = handleCreate(key);
ci.addCreate(id, result);
}
return result;
}
public void updateVisibleIDs(Map result) {
if (visible) {
Iterator iter = getSupportedIDs().iterator();
while (iter.hasNext()) {
result.put(iter.next(), this);
}
}
}
public String getDisplayName(String id, Locale locale) {
if (visible) {
Set cache = getSupportedIDs();
if (cache.contains(id)) {
return handleGetDisplayName(id, locale);
}
}
return null;
}
/**
* Subclasses implement this instead of create.
*/
protected abstract Object handleCreate(Key key);
/**
* Subclasses implement this instead of getSupportedIDs. Any
* id known to and handled by this class should be included in
* the returned Set.
*/
protected abstract Set handleGetSupportedIDs();
/**
* Subclasses implement this instead of getDisplayName.
* Return the display name for the (visible) id in the
* provided locale. The default implementation just returns
* the id.
*/
protected String handleGetDisplayName(String id, Locale locale) {
return id;
}
}
/**
* A subclass of MultipleKeyFactory that uses LocaleKeys. It is
* able to optionally 'hide' more specific locales with more general
* locales that it supports.
*/
public static abstract class LocaleKeyFactory extends MultipleKeyFactory {
protected final boolean hides;
public static abstract class LocaleKeyFactory implements Factory {
protected final String name;
protected final int coverage;
/**
* Create a LocaleKeyFactory.
* Coverage value indicating that the factory makes
* its locales visible, and does not cover more specific
* locales.
*/
public LocaleKeyFactory(boolean visible, boolean hides) {
super(visible);
public static final int VISIBLE = 0;
this.hides = hides;
/**
* Coverage value indicating that the factory does not make
* its locales visible, and does not cover more specific
* locales.
*/
public static final int INVISIBLE = 1;
/**
* Coverage value indicating that the factory makes
* its locales visible, covers more specific
* locales, and provides localization for the covered
* locales.
*/
public static final int VISIBLE_COVERS = 2;
/**
* Coverage value indicating that the factory does not
* make its locales visible, covers more specific
* locales, and also does not allow the locales it
* covers to be visible.
*/
public static final int INVISIBLE_COVERS = 3;
/**
* Coverage value indicating that the factory makes
* its locales visible, covers more specific
* locales, but does not allow the locales it covers
* to be visible.
*/
public static final int VISIBLE_COVERS_REMOVE = 6;
/**
* Constructor used by subclasses.
*/
protected LocaleKeyFactory(int coverage) {
this.coverage = coverage;
this.name = null;
}
/**
* Override of superclass method. If this is visible, it will update
* result with the ids it supports. If this hides ids, more specific
* ids already in result will be remapped to this.
* Constructor used by subclasses.
*/
public void updateVisibleIDs(Map result) {
if (visible) {
Set cache = getSupportedIDs();
Map toRemap = new HashMap();
Iterator iter = cache.iterator();
while (iter.hasNext()) {
String id = (String)iter.next();
if (hides) {
int idlen = id.length();
Iterator miter = result.keySet().iterator();
while (miter.hasNext()) {
String mid = (String)miter.next();
if (mid.startsWith(id) &&
(mid.length() == idlen ||
mid.charAt(idlen) == '_')) {
toRemap.put(mid, this);
miter.remove();
}
}
}
toRemap.put(id, this);
}
result.putAll(toRemap);
}
}
/**
* Return a localized name for the locale represented by id.
*/
protected String handleGetDisplayName(String id, Locale locale) {
// use java's display name formatting for now
return LocaleUtility.getLocaleFromName(id).getDisplayName(locale);
}
}
/**
* A factory that creates a service based on the ICU locale data.
* Subclasses specify a prefix (default is LocaleElements), a
* semicolon-separated list of required resources, and a visible flag.
* This factory will search the ICU locale data for a bundle with
* the exact prefix. Then it will test whether the required resources
* are all in this exact bundle. If so, it instantiates the full
* resource bundle, and hands it to createServiceFromResource, which
* subclasses must implement. Otherwise it returns null.
*/
public static class ICUResourceBundleFactory extends MultipleKeyFactory {
protected final String name;
protected final String[][] requiredContents;
public ICUResourceBundleFactory(boolean visible) {
this((String)null, visible);
protected LocaleKeyFactory(int coverage, String name) {
this.coverage = coverage;
this.name = name;
}
/**
* A service factory based on ICU resource data in the LocaleElements resources.
*/
public ICUResourceBundleFactory(String requiredContents, boolean visible) {
this(ICULocaleData.LOCALE_ELEMENTS, requiredContents, visible);
}
/**
* Implement superclass abstract method. This checks the currentID of
* the key against the supported IDs, and passes the canonicalLocale and
* kind off to handleCreate (which subclasses must implement).
*/
public Object create(Key key) {
// System.out.println("factory: " + this + "create: " + key.currentID());
/**
* A service factory based on ICU resource data in resources
* with the given name. If requiredContents is not null, all
* listed resources must come directly from the same bundle.
*/
public ICUResourceBundleFactory(String name, String requiredContents, boolean visible) {
this(name, buildRcAndOr(requiredContents), true, visible);
}
if (getSupportedIDs().contains(key.currentID())) {
LocaleKey lkey = (LocaleKey)key;
Locale loc = lkey.canonicalLocale();
int kind = lkey.kind();
private static class Node {
public boolean test(ResourceBundle rb) {
return rb != null;
return handleCreate(loc, kind);
} else {
// System.out.println("IDs did not support: " + key.currentID());
// System.out.println(getSupportedIDs());
}
}
private static class ResourceNode {
String name;
}
private static class BoolNode extends Node {
BoolNode car;
BoolNode cdr;
}
private static String[][] buildRcAndOr(String requiredContents) {
String[][] rcAndOr = null;
if (requiredContents != null) {
rcAndOr = new String[][] { parseDelimitedString(requiredContents) };
}
return rcAndOr;
}
public ICUResourceBundleFactory(String[] rcOr, boolean visible) {
this(ICULocaleData.LOCALE_ELEMENTS, rcOr, visible);
}
public ICUResourceBundleFactory(String name, String[] rcOr, boolean visible) {
this(name, buildRcAndOr(rcOr), true, visible);
}
private static String[][] buildRcAndOr(String[] rcOr) {
String[][] rcOrAnd = null;
if (rcOr != null) {
rcOrAnd = new String[rcOr.length][];
for (int i = 0; i < rcOr.length; ++i) {
rcOrAnd[i] = parseDelimitedString(rcOr[i]);
}
}
return rcOrAnd;
}
public ICUResourceBundleFactory(String[][] rcOrAnd, boolean adopt, boolean visible) {
this(ICULocaleData.LOCALE_ELEMENTS, rcOrAnd, adopt, visible);
}
private static String[] parseDelimitedString(String str) {
if (str != null) {
ArrayList list = new ArrayList();
for (int i = 0, len = str.length();;) {
while (i < len && str.charAt(i) == ';') {
++i;
}
if (i == len) {
break;
}
int j = str.indexOf(';', i);
if (j == -1) {
j = len;
}
list.add(str.substring(i, j));
i = j;
}
return (String[])list.toArray(new String[list.size()]);
}
return null;
}
public ICUResourceBundleFactory(String name, String[][] rcOrAnd, boolean adopt, boolean visible) {
super(visible);
this.name = name;
/**
* Override of superclass method. This adjusts the result based
* on the coverage rule for this factory.
*/
public void updateVisibleIDs(Map result) {
Set cache = getSupportedIDs();
if (!adopt && rcOrAnd != null) {
rcOrAnd = (String[][])rcOrAnd.clone();
for (int i = 0; i < rcOrAnd.length; ++i) {
rcOrAnd[i] = (String[])(rcOrAnd[i].clone());
boolean visible = (coverage & 0x1) == 0;
boolean covers = (coverage & 0x2) != 0;
boolean removes = !visible || (coverage & 0x4) != 0;
// System.out.println("vis: " + visible + " covers: " + covers + " removes: " + removes);
Map toRemap = new HashMap();
Iterator iter = cache.iterator();
while (iter.hasNext()) {
String id = (String)iter.next();
if (covers) {
int idlen = id.length();
Iterator miter = result.keySet().iterator();
while (miter.hasNext()) {
String mid = (String)miter.next();
if (mid.startsWith(id) &&
(mid.length() == idlen ||
mid.charAt(idlen) == '_')) {
if (removes) {
miter.remove();
} else {
toRemap.put(mid, this);
}
}
}
}
if (!visible) {
result.remove(id);
} else {
toRemap.put(id, this);
}
}
this.requiredContents = rcOrAnd;
}
/**
* Overrides parent handleCreate call. Parent will filter out keys that it
* knows are not accepted by this factory before calling this method.
*/
protected Object handleCreate(Key key) {
Locale loc = LocaleUtility.getLocaleFromName(key.currentID());
if (acceptsLocale(loc)) {
ResourceBundle bundle = ICULocaleData.getResourceBundle(name, loc); // full resource bundle tree lookup
return createFromBundle(bundle, key);
}
return null;
}
/**
* Queries all the available locales in ICU and adds the names
* of those which it accepts to result. This is quite
* time-consuming so we don't want to do it more than once if
* we have to. This is only called if we are visible.
*/
protected Set handleGetSupportedIDs() {
Set result = new TreeSet(String.CASE_INSENSITIVE_ORDER);
Locale[] locales = ICULocaleData.getAvailableLocales(name);
for (int i = 0; i < locales.length; ++i) {
Locale locale = locales[i];
if (acceptsLocale(locale)) {
String str = LocaleUtility.canonicalLocaleString(locale.toString());
result.add(str);
}
}
return result;
}
result.putAll(toRemap);
}
/**
* Return a localized name for the locale represented by id.
*/
protected String handleGetDisplayName(String id, Locale locale) {
return LocaleUtility.getLocaleFromName(id).getDisplayName(locale);
public String getDisplayName(String id, Locale locale) {
if (locale == null) {
return id;
}
Locale loc = LocaleUtility.getLocaleFromName(id);
return loc.getDisplayName(locale);
}
/**
* Utility method used by create(Key). Subclasses can implement
* this instead of create.
*/
protected Object handleCreate(Locale loc, int kind) {
return null;
}
/**
* Return the set of ids that this factory supports (visible or
* otherwise). This can be called often and might need to be
* cached if it is expensive to create.
*/
protected abstract Set getSupportedIDs();
/**
* For debugging.
*/
public String toString() {
StringBuffer buf = new StringBuffer(super.toString());
if (name != null) {
buf.append(", name: ");
buf.append(name);
}
buf.append(", coverage: ");
String[] coverage_names = {
"visible", "invisible", "visible_covers", "invisible_covers", "????", "visible_covers_remove"
};
buf.append(coverage_names[coverage]);
return buf.toString();
}
}
/**
* A LocaleKeyFactory that just returns a single object for a kind/locale.
*/
public static class SimpleLocaleKeyFactory extends LocaleKeyFactory {
private final Object obj;
private final String id;
private final int kind;
public SimpleLocaleKeyFactory(Object obj, Locale locale, int kind, int coverage) {
this(obj, locale, kind, coverage, null);
}
public SimpleLocaleKeyFactory(Object obj, Locale locale, int kind, int coverage, String name) {
super(coverage, name);
this.obj = obj;
this.id = LocaleUtility.canonicalLocaleString(locale.toString());
this.kind = kind;
}
public Object create(Key key) {
LocaleKey lkey = (LocaleKey)key;
if (kind == LocaleKey.KIND_ANY || kind == lkey.kind()) {
String keyID = lkey.currentID();
if (id.equals(keyID) ||
((coverage & 0x2) != 0 && LocaleUtility.isFallbackOf(id, keyID))) {
return obj;
}
}
return null;
}
protected Set getSupportedIDs() {
return Collections.singleton(id);
}
public String toString() {
StringBuffer buf = new StringBuffer(super.toString());
buf.append(", id: ");
buf.append(id);
buf.append(", kind: ");
buf.append(kind);
return buf.toString();
}
}
/**
* A LocaleKeyFactory that creates a service based on the ICU locale data.
* This is a base class for most ICU factories. Subclasses instantiate it
* with a constructor that takes a bundle name, which determines the supported
* IDs. Subclasses then override handleCreate to create the actual service
* object. The default implementation returns a resource bundle.
*/
public static class ICUResourceBundleFactory extends LocaleKeyFactory {
protected final String bundleName;
/**
* Convenience constructor that uses the main ICU bundle name.
*/
public ICUResourceBundleFactory() {
this(ICULocaleData.LOCALE_ELEMENTS);
}
/**
* We only accept the locale if there is a bundle for this exact locale and if
* all the required resources are directly in this bundle (none is from an
* inherited bundle);
* A service factory based on ICU resource data in resources
* with the given name.
*/
protected boolean acceptsLocale(Locale loc) {
boolean debug = false;
if (debug) System.out.println("al name: " + name + " loc: '" + loc + "'");
try {
ResourceBundle bundle = ICULocaleData.loadResourceBundle(name, loc);
if (bundle == null) {
if (debug) System.out.println("no bundle");
return false;
}
if (requiredContents == null) {
if (debug) System.out.println("always accepts");
return true;
}
public ICUResourceBundleFactory(String bundleName) {
super(VISIBLE);
loop:
for (int i = 0; i < requiredContents.length; ++i) {
String[] andRC = requiredContents[i];
this.bundleName = bundleName;
}
for (int j = 0; j < andRC.length; ++j) {
try {
if (debug) System.out.println("al["+i+"]["+j+"] " + andRC[j]);
bundle.getObject(andRC[j]);
}
catch (MissingResourceException ex) {
if (debug) System.out.println("nope");
continue loop;
}
}
if (debug) System.out.println("ok");
return true;
}
}
catch (Exception e) {
Thread.dumpStack();
if (debug) System.out.println("whoops: " + e);
System.exit(0);
}
return false;
/**
* Return the supported IDs. This is the set of all locale names in ICULocaleData.
*/
protected Set getSupportedIDs() {
return ICULocaleData.getAvailableLocaleNameSet(bundleName);
}
/**
* Subclassers implement this to create their service object based on the bundle and key.
* The default implementation just returns the bundle.
*/
protected Object createFromBundle(ResourceBundle bundle, Key key) {
return bundle;
}
/**
* Create the service. The default implementation returns the resource bundle
* for the locale, ignoring kind.
*/
protected Object handleCreate(Locale loc, int kind) {
return ICULocaleData.getResourceBundle(bundleName, loc);
}
public String toString() {
return super.toString() + ", bundle: " + bundleName;
}
}
/**
@ -660,7 +589,11 @@ public class ICULocaleService extends ICUService {
return fallbackLocaleName;
}
protected Key createKey(String id) {
public Key createKey(String id) {
return LocaleKey.createWithCanonicalFallback(id, validateFallbackLocale());
}
public Key createKey(String id, int kind) {
return LocaleKey.createWithCanonicalFallback(id, validateFallbackLocale(), kind);
}
}

View file

@ -5,18 +5,21 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/impl/ICUService.java,v $
* $Date: 2002/09/14 21:36:29 $
* $Revision: 1.8 $
* $Date: 2002/10/02 20:20:21 $
* $Revision: 1.9 $
*
*******************************************************************************
*/
package com.ibm.icu.impl;
import com.ibm.icu.text.Collator;
import java.lang.ref.SoftReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
@ -58,12 +61,22 @@ import java.util.TreeMap;
* longer be located through it. Service objects generated by this
* factory and held by the client are unaffected.</p>
*
* <p>Internally, ICUService uses Keys to query factories and perform
* <p>ICUService uses Keys to query factories and perform
* fallback. The Key defines the canonical form of the id, and
* implements the fallback strategy. Custom Keys can be defined that
* parse complex IDs into components that Factories can more easily
* use. The Key can cache the results of this parsing to save
* repeated effort.</p>
* repeated effort. ICUService provides convenience APIs that
* take Strings and generate default Keys for use in querying.</p>
*
* <p>ICUService provides API to get the list of ids publicly
* supported by the service (although queries aren't restricted to
* this list). This list contains only 'simple' IDs, and not fully
* unique ids. Factories are associated with each simple ID and
* the responsible factory can also return a human-readable localized
* version of the simple ID, for use in user interfaces. ICUService
* can also provide a sorted collection of the all the localized visible
* ids.</p>
*
* <p>ICUService implements ICUNotifier, so that clients can register
* to receive notification when factories are added or removed from
@ -114,11 +127,22 @@ public class ICUService extends ICUNotifier {
/**
* Keys are used to communicate with factories to generate an
* instance of the service. They define how ids are
* instance of the service. Keys define how ids are
* canonicalized, provide both a current id and a current
* descriptor to use in querying the cache and factories, and
* determine the fallback strategy. The default key has no
* fallbacks.
* determine the fallback strategy.</p>
*
* <p>Keys provide both a currentDescriptor and a currentID.
* The descriptor contains an optional prefix, followed by '/'
* and the currentID. Factories that handle complex keys,
* for example number format factories that generate multiple
* kinds of formatters for the same locale, use the descriptor
* to provide a fully unique identifier for the service object,
* while using the currentID (in this case, the locale string),
* as the visible IDs that can be localized.
*
* <p> The default implementation of Key has no fallbacks and
* has no custom descriptors.</p>
*/
public static class Key {
private final String id;
@ -156,14 +180,14 @@ public class ICUService extends ICUNotifier {
/**
* Return the current descriptor. This implementation returns
* the current ID. The current descriptor is used to fully
* identify an instance of the service in the cache. The
* current ID is that part of the descriptor that a factory
* can examine to identify whether it handles the key. The
* factory can either parse the descriptor or use custom API
* on the key in order to instantiate the service.
* identify an instance of the service in the cache. A
* factory may handle all descriptors for an ID, or just a
* particular descriptor. The factory can either parse the
* descriptor or use custom API on the key in order to
* instantiate the service.
*/
public String currentDescriptor() {
return currentID();
return "/" + currentID();
}
/**
@ -185,6 +209,7 @@ public class ICUService extends ICUNotifier {
* a supported id.
*/
public static interface Factory {
/**
* Create a service object from the key, if this factory
* supports the key. Otherwise, return null.
@ -192,18 +217,26 @@ public class ICUService extends ICUNotifier {
public Object create(Key key);
/**
* Add IDs this factory publicly handles to the result map,
* with this factory as the value. If this factory hides IDs
* currently in result, it should remove or reset the mappings
* for those IDs. Result should contain only ids, not
* descriptors.
* Update the result IDs (not descriptors) to reflect the IDs
* this factory handles. This function and getDisplayName are
* used to support ICUService.getDisplayNames. Basically, the
* factory has to determine which IDs it will permit to be
* available, and of those, which it will provide localized
* display names for. In most cases this reflects the IDs that
* the factory directly supports. A factory might, however,
* 'cover' existing IDs already in result (for example, variant
* locales) and support them itself. In this case it needs to
* remap those IDs to itself if it wishes to provide the
* display names for them, or remove those IDs from result
* if it wishes them to be invisible.
*/
public void updateVisibleIDs(Map result);
/**
* Return the display name for this id in the provided locale.
* If the id is not visible or not defined by the factory,
* return null. This is an id, not a descriptor.
* This is an localized id, not a descriptor. If the id is
* not visible or not defined by the factory, return null.
* If locale is null, return id unchanged.
*/
public String getDisplayName(String id, Locale locale);
}
@ -211,11 +244,11 @@ public class ICUService extends ICUNotifier {
/**
* A default implementation of factory. This provides default
* implementations for subclasses, and implements a singleton
* factory that matches a single id and returns a single
* (possibly deferred-initialized) instance. If visible is
* true, updates the map passed to updateVisibleIDs with a
* mapping from id to itself. This ignores the key descriptor
* and only examines the id.
* factory that matches a single id and returns a single
* (possibly deferred-initialized) instance. This implements
* updateVisibleIDs to add a mapping from its ID to itself
* if visible is true, or to remove any existing mapping
* for its ID if visible is false.
*/
public static class SimpleFactory implements Factory {
protected Object instance;
@ -245,7 +278,8 @@ public class ICUService extends ICUNotifier {
}
/**
* Return the service instance if id equals the key's currentID.
* Return the service instance if the factory's id is equal to
* the key's currentID.
*/
public Object create(Key key) {
if (id.equals(key.currentID())) {
@ -255,19 +289,37 @@ public class ICUService extends ICUNotifier {
}
/**
* If visible, adds a mapping from id -> this to the result.
* If visible, adds a mapping from id -> this to the result,
* otherwise removes id from result.
*/
public void updateVisibleIDs(Map result) {
if (visible) result.put(id, this);
if (visible) {
result.put(id, this);
} else {
result.remove(id);
}
}
/**
* If id equals this.id, returns id regardless of locale, otherwise
* returns null.
*/
* If this.id equals id, returns id regardless of locale,
* otherwise returns null. (This default implementation has
* no localized id information.)
*/
public String getDisplayName(String id, Locale locale) {
return (visible && id.equals(this.id)) ? id : null;
return (visible && this.id.equals(id)) ? id : null;
}
/**
* For debugging.
*/
public String toString() {
StringBuffer buf = new StringBuffer(super.toString());
buf.append(", id: ");
buf.append(id);
buf.append(", visible: ");
buf.append(visible);
return buf.toString();
}
}
/**
@ -313,7 +365,7 @@ public class ICUService extends ICUNotifier {
*/
public Object getKey(Key key, String[] actualReturn) {
if (factories.size() == 0) {
return null;
return handleDefault(key, actualReturn);
}
boolean debug = false;
@ -353,7 +405,9 @@ public class ICUService extends ICUNotifier {
if (result != null) {
if (debug) System.out.println(name + " found with descriptor: " + currentDescriptor);
break outer;
}
} else {
if (debug) System.out.println("did not find: " + currentDescriptor + " in cache");
}
// first test of cache failed, so we'll have to update
// the cache if we eventually succeed.
@ -362,12 +416,16 @@ public class ICUService extends ICUNotifier {
int n = 0;
Iterator fi = factories.iterator();
while (fi.hasNext()) {
Object service = ((Factory)fi.next()).create(key);
Factory f = (Factory)fi.next();
if (debug) System.out.println("trying factory: " + f.toString());
Object service = f.create(key);
if (service != null) {
result = new CacheEntry(currentDescriptor, service);
if (debug) System.out.println(name + " factory cache with descriptor: " + currentDescriptor);
if (debug) System.out.println(name + " factory supported: " + currentDescriptor + ", caching");
break outer;
}
} else {
if (debug) System.out.println("factory did not support: " + currentDescriptor);
}
}
// prepare to load the cache with all additional ids that
@ -402,7 +460,12 @@ public class ICUService extends ICUNotifier {
}
if (actualReturn != null) {
actualReturn[0] = result.actualDescriptor;
// strip null prefix
if (result.actualDescriptor.indexOf("/") == 0) {
actualReturn[0] = result.actualDescriptor.substring(1);
} else {
actualReturn[0] = result.actualDescriptor;
}
}
if (debug) System.out.println("found in service: " + name);
@ -417,7 +480,7 @@ public class ICUService extends ICUNotifier {
if (debug) System.out.println("not found in service: " + name);
return null;
return handleDefault(key, actualReturn);
}
private SoftReference cacheref;
@ -432,6 +495,15 @@ public class ICUService extends ICUNotifier {
}
}
/**
* Default handler for this service if no factory in the list
* handled the key.
*/
protected Object handleDefault(Key key, String[] actualIDReturn) {
return null;
}
/**
* Return a snapshot of the visible IDs for this service. This
* set will not change as Factories are added or removed, but the
@ -459,7 +531,7 @@ public class ICUService extends ICUNotifier {
// grab the factory list and update it ourselves
try {
factoryLock.acquireRead();
idcache = new TreeMap(String.CASE_INSENSITIVE_ORDER);
idcache = new HashMap();
ListIterator lIter = factories.listIterator(factories.size());
while (lIter.hasPrevious()) {
Factory f = (Factory)lIter.previous();
@ -512,6 +584,15 @@ public class ICUService extends ICUNotifier {
return getDisplayNames(Locale.getDefault());
}
/**
* Convenience override of getDisplayNames(Locale, Collator) that
* uses the default collator for the locale as the comparator.
*/
public Map getDisplayNames(Locale locale) {
Collator col = Collator.getInstance(locale);
return getDisplayNames(locale, col);
}
/**
* Return a snapshot of the mapping from display names to visible
* IDs for this service. This set will not change as factories
@ -519,19 +600,19 @@ public class ICUService extends ICUNotifier {
* no guarantee that all and only the ids in the returned map will
* be visible and supported by the service in subsequent calls,
* nor is there any guarantee that the current display names match
* those in the set.
* those in the set. The display names are sorted based on the
* comparator provided.
*/
public Map getDisplayNames(Locale locale) {
public Map getDisplayNames(Locale locale, Comparator col) {
Map dncache = null;
LocaleRef ref = dnref;
if (ref != null) {
dncache = ref.get(locale);
dncache = ref.get(locale, col);
}
while (dncache == null) {
synchronized (this) {
if (ref == dnref || dnref == null) {
dncache = new TreeMap(String.CASE_INSENSITIVE_ORDER);
//dncache = new TreeMap(/* locale-specific collator */);
dncache = new TreeMap(col); // sorted
Map m = getVisibleIDMap();
Iterator ei = m.entrySet().iterator();
@ -543,30 +624,37 @@ public class ICUService extends ICUNotifier {
}
dncache = Collections.unmodifiableMap(dncache);
dnref = new LocaleRef(dncache, locale);
dnref = new LocaleRef(dncache, locale, col);
} else {
ref = dnref;
dncache = ref.get(locale);
dncache = ref.get(locale, col);
}
}
}
return dncache;
}
// we define a class so we get atomic simultaneous access to both the
// locale and corresponding map
private static class LocaleRef {
final Locale locale;
final SoftReference ref;
LocaleRef(Map dnCache, Locale locale) {
// we define a class so we get atomic simultaneous access to the
// locale, comparator, and corresponding map.
private static class LocaleRef {
private final Locale locale;
private SoftReference ref;
private Comparator col;
LocaleRef(Map dnCache, Locale locale, Comparator col) {
this.locale = locale;
this.col = col;
this.ref = new SoftReference(dnCache);
}
Map get(Locale locale) {
if (this.locale.equals(locale)) {
return (Map)ref.get();
Map get(Locale locale, Comparator col) {
Map m = (Map)ref.get();
if (m != null &&
this.locale.equals(locale) &&
(this.col == col || (this.col != null && this.col.equals(col)))) {
return m;
}
return null;
}
@ -602,8 +690,8 @@ public class ICUService extends ICUNotifier {
* getVisibleIDs if visible is true.
*/
public Factory registerObject(Object obj, String id, boolean visible) {
id = createKey(id).canonicalID();
return registerFactory(new SimpleFactory(obj, id, visible));
String canonicalID = createKey(id).canonicalID();
return registerFactory(new SimpleFactory(obj, canonicalID, visible));
}
/**
@ -682,12 +770,20 @@ public class ICUService extends ICUNotifier {
factories.clear();
}
/**
* Return true if the service is in its default state. The default
* implementation returns true if there are no factories registered.
*/
public boolean isDefault() {
return factories.size() == 0;
}
/**
* Create a key from an id. This creates a Key instance.
* Subclasses can override to define more useful keys appropriate
* to the factories they accept.
*/
protected Key createKey(String id) {
public Key createKey(String id) {
return new Key(id);
}

View file

@ -5,8 +5,8 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/impl/LocaleUtility.java,v $
* $Date: 2002/09/14 21:36:29 $
* $Revision: 1.5 $
* $Date: 2002/10/02 20:20:21 $
* $Revision: 1.6 $
* *****************************************************************************************
*/
@ -70,6 +70,14 @@ public class LocaleUtility {
}
/**
* Convenience method that calls canonicalLocaleString(String) with
* locale.toString();
*/
public static String canonicalLocaleString(Locale locale) {
return canonicalLocaleString(locale.toString());
}
/**
* You'd think that Locale canonicalizes, since it munges the
* renamed languages, but it doesn't quite. It forces the region

View file

@ -5,14 +5,20 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/text/BreakIterator.java,v $
* $Date: 2002/03/20 05:11:15 $
* $Revision: 1.8 $
* $Date: 2002/10/02 20:20:21 $
* $Revision: 1.9 $
*
*****************************************************************************************
*/
package com.ibm.icu.text;
import com.ibm.icu.impl.ICULocaleData;
import com.ibm.icu.impl.ICULocaleService;
import com.ibm.icu.impl.ICULocaleService.LocaleKey;
import com.ibm.icu.impl.ICULocaleService.ICUResourceBundleFactory;
import com.ibm.icu.impl.ICUService.Factory;
import com.ibm.icu.impl.ICUService.Key;
import com.ibm.icu.impl.LocaleUtility;
import java.io.InputStream;
import java.io.IOException;
@ -397,11 +403,18 @@ public abstract class BreakIterator implements Cloneable
*/
public abstract void setText(CharacterIterator newText);
public static final int KIND_CHARACTER = 0;
public static final int KIND_WORD = 1;
public static final int KIND_LINE = 2;
public static final int KIND_SENTENCE = 3;
public static final int KIND_TITLE = 4;
/*
private static final int CHARACTER_INDEX = 0;
private static final int WORD_INDEX = 1;
private static final int LINE_INDEX = 2;
private static final int SENTENCE_INDEX = 3;
private static final int TITLE_INDEX = 4;
*/
private static final SoftReference[] iterCache = new SoftReference[5];
/**
@ -423,10 +436,7 @@ public abstract class BreakIterator implements Cloneable
*/
public static BreakIterator getWordInstance(Locale where)
{
return getBreakInstance(where,
WORD_INDEX,
"WordBreakRules",
"WordBreakDictionary");
return getBreakInstance(where, KIND_WORD);
}
/**
@ -450,10 +460,7 @@ public abstract class BreakIterator implements Cloneable
*/
public static BreakIterator getLineInstance(Locale where)
{
return getBreakInstance(where,
LINE_INDEX,
"LineBreakRules",
"LineBreakDictionary");
return getBreakInstance(where, KIND_LINE);
}
/**
@ -477,10 +484,7 @@ public abstract class BreakIterator implements Cloneable
*/
public static BreakIterator getCharacterInstance(Locale where)
{
return getBreakInstance(where,
CHARACTER_INDEX,
"CharacterBreakRules",
"CharacterBreakDictionary");
return getBreakInstance(where, KIND_CHARACTER);
}
/**
@ -501,10 +505,7 @@ public abstract class BreakIterator implements Cloneable
*/
public static BreakIterator getSentenceInstance(Locale where)
{
return getBreakInstance(where,
SENTENCE_INDEX,
"SentenceBreakRules",
"SentenceBreakDictionary");
return getBreakInstance(where, KIND_SENTENCE);
}
/**
@ -525,19 +526,64 @@ public abstract class BreakIterator implements Cloneable
*/
public static BreakIterator getTitleInstance(Locale where)
{
return getBreakInstance(where,
TITLE_INDEX,
"TitleBreakRules",
"TitleBreakDictionary");
return getBreakInstance(where, KIND_TITLE);
}
private static BreakIterator getBreakInstance(Locale where,
int type,
String rulesName,
String dictionaryName) {
public static Object register(BreakIterator iter, Locale locale, int kind) {
try {
return getService().registerObject(iter, locale, kind);
}
catch (IndexOutOfBoundsException e) {
throw new IllegalArgumentException("unknown kind: " + kind);
}
}
if (iterCache[type] != null) {
BreakIteratorCache cache = (BreakIteratorCache) iterCache[type].get();
public static boolean unregister(Object key) {
if (service != null) {
return service.unregisterFactory((Factory)key);
}
return false;
}
private static ICULocaleService service;
private static ICULocaleService getService() {
if (service == null) {
ICULocaleService newService = new ICULocaleService("BreakIterator");
class RBBreakIteratorFactory extends ICUResourceBundleFactory {
protected Object handleCreate(Locale loc, int kind) {
return createBreakInstance(loc, kind);
}
}
newService.registerFactory(new RBBreakIteratorFactory());
synchronized (BreakIterator.class) {
if (service == null) {
service = newService;
}
}
}
return service;
}
private static final String[] KIND_NAMES = {
"Character", "Word", "Line", "Sentence", "Title"
};
private static BreakIterator createBreakInstance(Locale locale, int kind) {
String prefix = KIND_NAMES[kind];
return createBreakInstance(locale,
kind,
prefix + "BreakRules",
prefix + "BreakDictionary");
}
// end of registration
private static BreakIterator getBreakInstance(Locale where, int kind) {
if (iterCache[kind] != null) {
BreakIteratorCache cache = (BreakIteratorCache) iterCache[kind].get();
if (cache != null) {
if (cache.getLocale().equals(where)) {
return cache.createBreakInstance();
@ -545,17 +591,14 @@ public abstract class BreakIterator implements Cloneable
}
}
BreakIterator result = createBreakInstance(where,
type,
rulesName,
dictionaryName);
BreakIterator result = createBreakInstance(where, kind);
BreakIteratorCache cache = new BreakIteratorCache(where, result);
iterCache[type] = new SoftReference(cache);
iterCache[kind] = new SoftReference(cache);
return result;
}
private static BreakIterator createBreakInstance(Locale where,
int type,
int kind,
String rulesName,
String dictionaryName) {
@ -566,10 +609,10 @@ public abstract class BreakIterator implements Cloneable
String rules = bundle.getString(rulesName);
if (classNames[type].equals("RuleBasedBreakIterator")) {
if (classNames[kind].equals("RuleBasedBreakIterator")) {
return new RuleBasedBreakIterator(rules);
}
else if (classNames[type].equals("DictionaryBasedBreakIterator")) {
else if (classNames[kind].equals("DictionaryBasedBreakIterator")) {
try {
// System.out.println(dictionaryName);
Object t = bundle.getObject(dictionaryName);
@ -586,7 +629,7 @@ public abstract class BreakIterator implements Cloneable
}
else
throw new IllegalArgumentException("Invalid break iterator class \"" +
classNames[type] + "\"");
classNames[kind] + "\"");
}
/**
@ -596,8 +639,11 @@ public abstract class BreakIterator implements Cloneable
*/
public static synchronized Locale[] getAvailableLocales()
{
// returns all locales
return ICULocaleData.getAvailableLocales();
if (service == null) {
return ICULocaleData.getAvailableLocales();
} else {
return service.getAvailableLocales();
}
}
private static final class BreakIteratorCache {

View file

@ -574,7 +574,7 @@ public abstract class DateFormat extends Format {
*/
public static Locale[] getAvailableLocales()
{
return ICULocaleData.getAvailableLocales("DateTimePatterns");
return ICULocaleData.getAvailableLocales();
}
/**

View file

@ -5,8 +5,8 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/text/NumberFormat.java,v $
* $Date: 2002/09/14 21:36:28 $
* $Revision: 1.14 $
* $Date: 2002/10/02 20:20:21 $
* $Revision: 1.15 $
*
*****************************************************************************************
*/
@ -21,6 +21,7 @@ import java.text.FieldPosition;
import java.text.Format;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Locale;
@ -162,7 +163,7 @@ import com.ibm.icu.impl.LocaleUtility;
*
* see DecimalFormat
* see java.text.ChoiceFormat
* @version $Revision: 1.14 $
* @version $Revision: 1.15 $
* @author Mark Davis
* @author Helena Shih
* @author Alan Liu
@ -483,18 +484,19 @@ public abstract class NumberFormat extends Format{
public static final int FORMAT_INTEGER = INTEGERSTYLE;
/**
* Return true if this factory will 'hide' other locales that
* Return true if this factory will 'cover' other locales that
* are more specific than the ones in this factory. E.g., if
* this 'hides' other locales, then by supporting the 'en'
* this 'covers' other locales, then by supporting the 'en'
* locale, this also supports 'en_US', 'en_US_ETC' and so on,
* even though only the 'en' locale is listed.
*/
public abstract boolean hasGenericLocales();
public abstract boolean covers();
/**
* Return an array of the locales directly supported by this factory.
* Return an unmodifiable collection of the locale names directly
* supported by this factory.
*/
public abstract Locale[] getSupportedLocales();
public abstract Set getSupportedLocaleNames();
/**
* Return a number format of the appropriate type. If the locale
@ -505,20 +507,20 @@ public abstract class NumberFormat extends Format{
}
public static abstract class SimpleNumberFormatFactory extends NumberFormatFactory {
final Locale locale;
final boolean isGeneric;
final Set localeNames;
final boolean covers;
public SimpleNumberFormatFactory(Locale locale, boolean isGeneric) {
this.locale = locale;
this.isGeneric = isGeneric;
public SimpleNumberFormatFactory(Locale locale, boolean covers) {
localeNames = Collections.singleton(LocaleUtility.canonicalLocaleString(locale));
this.covers = covers;
}
public final boolean hasGenericLocales() {
return isGeneric;
public final boolean covers() {
return covers;
}
public final Locale[] getSupportedLocales() {
return new Locale[] { locale };
public final Set getSupportedLocaleNames() {
return localeNames;
}
}
@ -526,25 +528,17 @@ public abstract class NumberFormat extends Format{
private NumberFormatFactory delegate;
NFFactory(NumberFormatFactory delegate) {
super(true, delegate.hasGenericLocales());
super(delegate.covers() ? VISIBLE_COVERS : VISIBLE);
this.delegate = delegate;
}
protected Object handleCreate(Key key) {
NFKey nfkey = (NFKey)key;
Locale loc = nfkey.canonicalLocale();
int choice = nfkey.choice();
return delegate.createFormat(loc, choice);
protected Object handleCreate(Locale loc, int kind) {
return delegate.createFormat(loc, kind);
}
protected Set handleGetSupportedIDs() {
Locale[] locales = delegate.getSupportedLocales();
Set result = new HashSet();
for (int i = 0; i < locales.length; ++i) {
result.add(locales.toString());
}
return result;
protected Set getSupportedIDs() {
return delegate.getSupportedLocaleNames();
}
}
@ -553,30 +547,10 @@ public abstract class NumberFormat extends Format{
* @return available locales
*/
public static Locale[] getAvailableLocales() {
// return ICULocaleData.getAvailableLocales("NumberPatterns");
return getService().getAvailableLocales();
}
private static final class NFKey extends LocaleKey {
private int choice;
private static String[] CHOICE_NAMES = {
"number", "currency", "percent", "scientific", "integer"
};
private NFKey(String id, String canonicalID, String canonicalFallback, int choice) {
super(id, canonicalID, canonicalFallback, CHOICE_NAMES[choice]);
this.choice = choice;
}
int choice() {
return choice;
}
static NFKey createKey(ICULocaleService service, Locale locale, int choice) {
String id = LocaleUtility.canonicalLocaleString(locale.toString());
String fallback = service.validateFallbackLocale();
return new NFKey(id, id, fallback, choice);
if (service == null) {
return ICULocaleData.getAvailableLocales();
} else {
return service.getAvailableLocales();
}
}
@ -597,46 +571,36 @@ public abstract class NumberFormat extends Format{
* registerInstance).
*/
public static boolean unregister(Object registryKey) {
return getService().unregisterFactory((Factory)registryKey);
if (service == null) {
return false;
} else {
return service.unregisterFactory((Factory)registryKey);
}
}
private static ICULocaleService service = null;
private static ICULocaleService getService() {
if (service == null) {
final String[][] pattern = {
new String[] { "NumberPatterns" },
new String[] { "NumberElements" },
new String[] { "CurrencyElements" },
};
class RBNumberFormatFactory extends ICUResourceBundleFactory {
RBNumberFormatFactory() {
super ("LocaleElements", pattern, true, true);
}
protected Object handleCreate(Key key) {
NFKey nfkey = (NFKey)key;
Locale locale = nfkey.currentLocale();
// System.out.println("testing locale: " + locale);
if (acceptsLocale(locale)) {
// System.out.println("creating with locale: " + nfkey.canonicalLocale());
return createInstance(nfkey.canonicalLocale(), nfkey.choice());
}
// System.out.println("did not support locale");
return null;
protected Object handleCreate(Locale loc, int kind) {
return createInstance(loc, kind);
}
}
ICULocaleService newService = new ICULocaleService("NumberFormat");
newService.registerFactory(new RBNumberFormatFactory());
service = newService; // atomic
synchronized (NumberFormat.class) {
if (service == null) {
service = newService;
}
}
}
return service;
}
// ===== End of factory stuff =====
/**
* Overrides hashCode
*/
@ -800,8 +764,7 @@ public abstract class NumberFormat extends Format{
// Hook for service
private static NumberFormat getInstance(Locale desiredLocale, int choice) {
ICULocaleService service = getService();
NFKey key = NFKey.createKey(service, desiredLocale, choice);
NumberFormat result = (NumberFormat)service.getKey(key);
NumberFormat result = (NumberFormat)service.get(desiredLocale, choice);
//System.out.println("desired locale: " + desiredLocale + " service result:" + result);

View file

@ -5,8 +5,8 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/util/BuddhistCalendar.java,v $
* $Date: 2002/02/16 03:06:24 $
* $Revision: 1.8 $
* $Date: 2002/10/02 20:20:25 $
* $Revision: 1.9 $
*
*****************************************************************************************
*/
@ -187,4 +187,20 @@ public class BuddhistCalendar extends GregorianCalendar {
}
return super.handleGetLimit(field, limitType);
}
private static CalendarFactory factory;
public static CalendarFactory factory() {
if (factory == null) {
factory = new CalendarFactory() {
public Calendar create(TimeZone tz, Locale loc) {
return new BuddhistCalendar(tz, loc);
}
public String factoryName() {
return "Buddhist";
}
};
}
return factory;
}
}

View file

@ -7,6 +7,14 @@
package com.ibm.icu.util;
import com.ibm.icu.impl.ICULocaleData;
import com.ibm.icu.impl.ICUService;
import com.ibm.icu.impl.ICUService.Key;
import com.ibm.icu.impl.ICUService.Factory;
import com.ibm.icu.impl.ICULocaleService;
import com.ibm.icu.impl.ICULocaleService.ICUResourceBundleFactory;
import com.ibm.icu.impl.ICULocaleService.LocaleKey;
import com.ibm.icu.impl.ICULocaleService.LocaleKeyFactory;
import com.ibm.icu.impl.LocaleUtility;
import com.ibm.icu.text.DateFormat;
import com.ibm.icu.text.DateFormatSymbols;
import com.ibm.icu.text.SimpleDateFormat;
@ -16,11 +24,15 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Hashtable;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
/**
* <code>Calendar</code> is an abstract base class for converting between
@ -620,7 +632,7 @@ import java.util.ResourceBundle;
* @see GregorianCalendar
* @see TimeZone
* @see DateFormat
* @version $Revision: 1.30 $ $Date: 2002/08/21 18:39:56 $
* @version $Revision: 1.31 $ $Date: 2002/10/02 20:20:25 $
* @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu, Laura Werner
* @since JDK1.1
*/
@ -1422,7 +1434,7 @@ public abstract class Calendar implements Serializable, Cloneable {
*/
public static synchronized Calendar getInstance()
{
return new GregorianCalendar();
return getInstance(TimeZone.getDefault(), Locale.getDefault(), null);
}
/**
@ -1432,7 +1444,7 @@ public abstract class Calendar implements Serializable, Cloneable {
*/
public static synchronized Calendar getInstance(TimeZone zone)
{
return new GregorianCalendar(zone, Locale.getDefault());
return getInstance(zone, Locale.getDefault(), null);
}
/**
@ -1442,7 +1454,7 @@ public abstract class Calendar implements Serializable, Cloneable {
*/
public static synchronized Calendar getInstance(Locale aLocale)
{
return new GregorianCalendar(TimeZone.getDefault(), aLocale);
return getInstance(TimeZone.getDefault(), aLocale, null);
}
/**
@ -1452,20 +1464,138 @@ public abstract class Calendar implements Serializable, Cloneable {
* @return a Calendar.
*/
public static synchronized Calendar getInstance(TimeZone zone,
Locale aLocale)
Locale aLocale) {
return getInstance(zone, aLocale, null);
}
// ==== Factory Stuff ====
/**
* Return a calendar of for the TimeZone and locale. If calType is
* not null, looks in the collection of CalendarFactories for a match
* and uses that factory to instantiate the calendar. Otherwise, it
* uses the default factory that has been registered for that locale.
*/
public static synchronized Calendar getInstance(TimeZone zone,
Locale locale,
String factoryName)
{
return new GregorianCalendar(zone, aLocale);
CalendarFactory factory = null;
if (factoryName != null) {
factory = (CalendarFactory)getFactoryMap().get(factoryName);
}
if (factory == null && service != null) {
factory = (CalendarFactory)service.get(locale);
}
if (factory == null) {
return new GregorianCalendar(zone, locale);
} else {
return factory.create(zone, locale);
}
}
/**
* Gets the list of locales for which Calendars are installed.
* @return the list of locales for which Calendars are installed.
*/
public static synchronized Locale[] getAvailableLocales()
public static Locale[] getAvailableLocales()
{
return DateFormat.getAvailableLocales();
return service == null
? ICULocaleData.getAvailableLocales()
: service.getAvailableLocales();
}
private static Map factoryMap;
private static Map getFactoryMap() {
if (factoryMap == null) {
Map m = new HashMap(5);
addFactory(m, BuddhistCalendar.factory());
addFactory(m, ChineseCalendar.factory());
addFactory(m, GregorianCalendar.factory());
addFactory(m, HebrewCalendar.factory());
addFactory(m, IslamicCalendar.factory());
addFactory(m, JapaneseCalendar.factory());
factoryMap = m;
}
return factoryMap;
}
private static void addFactory(Map m, CalendarFactory f) {
m.put(f.factoryName(), f);
}
/**
* Return a set of all the registered calendar factory names.
*/
public static Set getCalendarFactoryNames() {
return Collections.unmodifiableSet(getFactoryMap().keySet());
}
/**
* Register a new CalendarFactory. getInstance(TimeZone, Locale, String) will
* try to locate a registered factories matching the factoryName. Only registered
* factories will be found.
*/
public static void registerFactory(CalendarFactory factory) {
if (factory == null) {
throw new IllegalArgumentException("Factory must not be null");
}
getFactoryMap().put(factory.factoryName(), factory);
}
/**
* Registers a default CalendarFactory for the provided locale.
* If covers is true, this factory is also used for all locales
* that are more specific than the provided locale. The returned
* object is a key that can be used to unregister this
* CalendarFactory. If the factory has not already been
* registered with registerFactory, it will be.
*/
public static Object register(CalendarFactory factory, Locale locale, boolean covers) {
if (factory == null) {
throw new IllegalArgumentException("calendar must not be null");
}
registerFactory(factory);
return getService().registerObject(factory, locale, covers
? LocaleKeyFactory.VISIBLE_COVERS
: LocaleKeyFactory.VISIBLE);
}
/**
* Unregister the CalendarFactory associated with this key
* (obtained from register).
*/
public static boolean unregister(Object registryKey) {
return service == null
? false
: service.unregisterFactory((Factory)registryKey);
}
private static ICULocaleService service = null;
private static ICULocaleService getService() {
if (service == null) {
ICULocaleService newService = new ICULocaleService("Calendar");
class RBCalendarFactory extends ICUResourceBundleFactory {
protected Object handleCreate(Locale locale, int kind) {
return GregorianCalendar.factory();
}
}
newService.registerFactory(new RBCalendarFactory());
synchronized (Calendar.class) {
if (service == null) {
service = newService;
}
}
}
return service;
}
// ==== End of factory Stuff ====
/**
* Gets this Calendar's current time.
* @return the current time.

View file

@ -3,8 +3,8 @@
* others. All Rights Reserved.
*********************************************************************
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/util/ChineseCalendar.java,v $
* $Date: 2002/02/16 03:06:26 $
* $Revision: 1.10 $
* $Date: 2002/10/02 20:20:25 $
* $Revision: 1.11 $
*/
package com.ibm.icu.util;
import com.ibm.icu.lang.*;
@ -550,8 +550,14 @@ public class ChineseCalendar extends Calendar {
*/
private boolean hasNoMajorSolarTerm(int newMoon) {
int mst = majorSolarTerm(newMoon);
int nmn = newMoonNear(newMoon + SYNODIC_GAP, true);
int mstt = majorSolarTerm(nmn);
return mst == mstt;
/*
return majorSolarTerm(newMoon) ==
majorSolarTerm(newMoonNear(newMoon + SYNODIC_GAP, true));
*/
}
//------------------------------------------------------------------
@ -779,4 +785,20 @@ public class ChineseCalendar extends Calendar {
return julianDay - 1;
}
private static CalendarFactory factory;
public static CalendarFactory factory() {
if (factory == null) {
factory = new CalendarFactory() {
public Calendar create(TimeZone tz, Locale loc) {
return new ChineseCalendar(tz, loc);
}
public String factoryName() {
return "Chinese";
}
};
}
return factory;
}
}

View file

@ -5,8 +5,8 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/util/Currency.java,v $
* $Date: 2002/09/14 21:36:30 $
* $Revision: 1.6 $
* $Date: 2002/10/02 20:20:25 $
* $Revision: 1.7 $
*
*******************************************************************************
*/
@ -56,20 +56,23 @@ public class Currency implements Serializable {
private static ICULocaleService getService() {
if (service == null) {
service = new ICULocaleService("Currency");
ICULocaleService newService = new ICULocaleService("Currency");
class CurrencyFactory extends ICUResourceBundleFactory {
CurrencyFactory() {
super("CurrencyElements", true);
}
protected Object createFromBundle(ResourceBundle bundle, Key key) {
protected Object handleCreate(Locale loc, int kind) {
ResourceBundle bundle = ICULocaleData.getLocaleElements(loc);
String[] ce = bundle.getStringArray("CurrencyElements");
// System.out.println("currency factory loc: " + loc + " rb: " + bundle + "ce[1]" + ce[1]);
return new Currency(ce[1]);
}
}
service.registerFactory(new CurrencyFactory());
newService.registerFactory(new CurrencyFactory());
synchronized (Currency.class) {
if (service == null) {
service = newService;
}
}
}
return service;
}

View file

@ -902,4 +902,20 @@ public class GregorianCalendar extends Calendar {
return julianDay;
}
private static CalendarFactory factory;
public static CalendarFactory factory() {
if (factory == null) {
factory = new CalendarFactory() {
public Calendar create(TimeZone tz, Locale loc) {
return new GregorianCalendar(tz, loc);
}
public String factoryName() {
return "Gregorian";
}
};
}
return factory;
}
}

View file

@ -5,8 +5,8 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/util/HebrewCalendar.java,v $
* $Date: 2002/08/07 03:10:20 $
* $Revision: 1.9 $
* $Date: 2002/10/02 20:20:24 $
* $Revision: 1.10 $
*
*****************************************************************************************
*/
@ -765,4 +765,20 @@ public class HebrewCalendar extends Calendar {
return (int) (day + 347997);
}
private static CalendarFactory factory;
public static CalendarFactory factory() {
if (factory == null) {
factory = new CalendarFactory() {
public Calendar create(TimeZone tz, Locale loc) {
return new HebrewCalendar(tz, loc);
}
public String factoryName() {
return "Hebrew";
}
};
}
return factory;
}
}

View file

@ -5,8 +5,8 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/util/IslamicCalendar.java,v $
* $Date: 2002/08/07 03:10:18 $
* $Revision: 1.11 $
* $Date: 2002/10/02 20:20:24 $
* $Revision: 1.12 $
*
*****************************************************************************************
*/
@ -560,4 +560,20 @@ public class IslamicCalendar extends Calendar {
internalSet(DAY_OF_MONTH, dayOfMonth);
internalSet(DAY_OF_YEAR, dayOfYear);
}
private static CalendarFactory factory;
public static CalendarFactory factory() {
if (factory == null) {
factory = new CalendarFactory() {
public Calendar create(TimeZone tz, Locale loc) {
return new IslamicCalendar(tz, loc);
}
public String factoryName() {
return "Islamic";
}
};
}
return factory;
}
}

View file

@ -5,8 +5,8 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/util/JapaneseCalendar.java,v $
* $Date: 2002/02/16 03:06:29 $
* $Revision: 1.8 $
* $Date: 2002/10/02 20:20:24 $
* $Revision: 1.9 $
*
*****************************************************************************************
*/
@ -535,4 +535,20 @@ public class JapaneseCalendar extends GregorianCalendar {
return super.handleGetLimit(field, limitType);
}
}
private static CalendarFactory factory;
public static CalendarFactory factory() {
if (factory == null) {
factory = new CalendarFactory() {
public Calendar create(TimeZone tz, Locale loc) {
return new JapaneseCalendar(tz, loc);
}
public String factoryName() {
return "Japanese";
}
};
}
return factory;
}
}