001: /**
002: *******************************************************************************
003: * Copyright (C) 2001-2006, International Business Machines Corporation and *
004: * others. All Rights Reserved. *
005: *******************************************************************************
006: */package com.ibm.icu.util;
007:
008: import java.io.Serializable;
009: import java.text.ChoiceFormat;
010: import java.text.ParsePosition;
011: import java.util.Locale;
012: import java.util.MissingResourceException;
013:
014: import com.ibm.icu.impl.ICUDebug;
015: import com.ibm.icu.impl.ICUResourceBundle;
016: import com.ibm.icu.impl.LocaleUtility;
017:
018: /**
019: * A class encapsulating a currency, as defined by ISO 4217. A
020: * <tt>Currency</tt> object can be created given a <tt>Locale</tt> or
021: * given an ISO 4217 code. Once created, the <tt>Currency</tt> object
022: * can return various data necessary to its proper display:
023: *
024: * <ul><li>A display symbol, for a specific locale
025: * <li>The number of fraction digits to display
026: * <li>A rounding increment
027: * </ul>
028: *
029: * The <tt>DecimalFormat</tt> class uses these data to display
030: * currencies.
031: *
032: * <p>Note: This class deliberately resembles
033: * <tt>java.util.Currency</tt> but it has a completely independent
034: * implementation, and adds features not present in the JDK.
035: * @author Alan Liu
036: * @stable ICU 2.2
037: */
038: public class Currency extends MeasureUnit implements Serializable {
039: // using serialver from jdk1.4.2_05
040: private static final long serialVersionUID = -5839973855554750484L;
041: private static final boolean DEBUG = ICUDebug.enabled("currency");
042: /**
043: * ISO 4217 3-letter code.
044: */
045: private String isoCode;
046:
047: /**
048: * Selector for getName() indicating a symbolic name for a
049: * currency, such as "$" for USD.
050: * @stable ICU 2.6
051: */
052: public static final int SYMBOL_NAME = 0;
053:
054: /**
055: * Selector for ucurr_getName indicating the long name for a
056: * currency, such as "US Dollar" for USD.
057: * @stable ICU 2.6
058: */
059: public static final int LONG_NAME = 1;
060:
061: // begin registry stuff
062:
063: // shim for service code
064: /* package */static abstract class ServiceShim {
065: abstract ULocale[] getAvailableULocales();
066:
067: abstract Locale[] getAvailableLocales();
068:
069: abstract Currency createInstance(ULocale l);
070:
071: abstract Object registerInstance(Currency c, ULocale l);
072:
073: abstract boolean unregister(Object f);
074: }
075:
076: private static ServiceShim shim;
077:
078: private static ServiceShim getShim() {
079: // Note: this instantiation is safe on loose-memory-model configurations
080: // despite lack of synchronization, since the shim instance has no state--
081: // it's all in the class init. The worst problem is we might instantiate
082: // two shim instances, but they'll share the same state so that's ok.
083: if (shim == null) {
084: try {
085: Class cls = Class
086: .forName("com.ibm.icu.util.CurrencyServiceShim");
087: shim = (ServiceShim) cls.newInstance();
088: } catch (Exception e) {
089: if (DEBUG) {
090: e.printStackTrace();
091: }
092: throw new RuntimeException(e.getMessage());
093: }
094: }
095: return shim;
096: }
097:
098: /**
099: * Returns a currency object for the default currency in the given
100: * locale.
101: * @param locale the locale
102: * @return the currency object for this locale
103: * @stable ICU 2.2
104: */
105: public static Currency getInstance(Locale locale) {
106: return getInstance(ULocale.forLocale(locale));
107: }
108:
109: /**
110: * Returns a currency object for the default currency in the given
111: * locale.
112: * @draft ICU 3.2
113: * @provisional This API might change or be removed in a future release.
114: */
115: public static Currency getInstance(ULocale locale) {
116: String currency = locale.getKeywordValue("currency");
117: if (currency != null) {
118: return getInstance(currency);
119: }
120:
121: if (shim == null) {
122: return createCurrency(locale);
123: }
124:
125: return shim.createInstance(locale);
126: }
127:
128: /**
129: * Instantiate a currency from a resource bundle found in Locale loc.
130: */
131: /* package */static Currency createCurrency(ULocale loc) {
132: // TODO: check, this munging might not be required for ULocale
133: String country = loc.getCountry();
134: String variant = loc.getVariant();
135: if (variant.equals("PREEURO") || variant.equals("EURO")) {
136: country = country + '_' + variant;
137: }
138: ICUResourceBundle bundle = (ICUResourceBundle) ICUResourceBundle
139: .getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,
140: "CurrencyData",
141: ICUResourceBundle.ICU_DATA_CLASS_LOADER);
142: if (bundle == null) {
143: //throw new MissingResourceException()
144: }
145: ICUResourceBundle cm = bundle.get("CurrencyMap");
146:
147: // Do a linear search
148: String curriso = null;
149: try {
150: curriso = cm.getString(country);
151: if (curriso != null) {
152: return new Currency(curriso);
153: }
154: } catch (MissingResourceException ex) {
155: try {
156: // a deprecated ISO code may have been passed
157: // try to get the current country code
158: String rep = ULocale.getCurrentCountryID(country);
159: if (DEBUG)
160: System.out.println("DEBUG: oldID: " + country
161: + " newID:" + rep);
162: // here pointer comparison is valid since getCurrentCountryID
163: // will return the input string if there is no replacement
164: if (rep != country) {
165: curriso = cm.getString(rep);
166: if (curriso != null) {
167: return new Currency(curriso);
168: }
169: }
170: } catch (MissingResourceException e) {
171: //do nothing
172: }
173: }
174: return null;
175: /*
176: for (int i=0; i<cm.length; ++i) {
177: if (country.equals((String) cm[i][0])) {
178: curriso = (String) cm[i][1];
179: break;
180: }
181: }
182:
183: Currency curr = null;
184: if (curriso != null) {
185:
186: curr = new Currency(curriso);
187:
188: // TODO: Determine valid and actual locale correctly.
189: ULocale uloc = bundle.getULocale();
190: curr.setLocale(uloc, uloc);
191: }
192: return curr;
193: */
194: }
195:
196: /**
197: * Returns a currency object given an ISO 4217 3-letter code.
198: * @param theISOCode the iso code
199: * @return the currency for this iso code
200: * @stable ICU 2.2
201: */
202: public static Currency getInstance(String theISOCode) {
203: return new Currency(theISOCode);
204: }
205:
206: /**
207: * Registers a new currency for the provided locale. The returned object
208: * is a key that can be used to unregister this currency object.
209: * @param currency the currency to register
210: * @param locale the ulocale under which to register the currency
211: * @return a registry key that can be used to unregister this currency
212: * @see #unregister
213: * @draft ICU 3.2
214: * @provisional This API might change or be removed in a future release.
215: */
216: public static Object registerInstance(Currency currency,
217: ULocale locale) {
218: return getShim().registerInstance(currency, locale);
219: }
220:
221: /**
222: * Unregister the currency associated with this key (obtained from
223: * registerInstance).
224: * @param registryKey the registry key returned from registerInstance
225: * @see #registerInstance
226: * @stable ICU 2.6
227: */
228: public static boolean unregister(Object registryKey) {
229: if (registryKey == null) {
230: throw new IllegalArgumentException(
231: "registryKey must not be null");
232: }
233: if (shim == null) {
234: return false;
235: }
236: return shim.unregister(registryKey);
237: }
238:
239: /**
240: * Return an array of the locales for which a currency
241: * is defined.
242: * @return an array of the available locales
243: * @stable ICU 2.2
244: */
245: public static Locale[] getAvailableLocales() {
246: if (shim == null) {
247: return ICUResourceBundle
248: .getAvailableLocales(ICUResourceBundle.ICU_BASE_NAME);
249: } else {
250: return shim.getAvailableLocales();
251: }
252: }
253:
254: /**
255: * Return an array of the ulocales for which a currency
256: * is defined.
257: * @return an array of the available ulocales
258: * @stable ICU 3.2
259: */
260: public static ULocale[] getAvailableULocales() {
261: if (shim == null) {
262: return ICUResourceBundle
263: .getAvailableULocales(ICUResourceBundle.ICU_BASE_NAME);
264: } else {
265: return shim.getAvailableULocales();
266: }
267: }
268:
269: // end registry stuff
270:
271: /**
272: * Return a hashcode for this currency.
273: * @stable ICU 2.2
274: */
275: public int hashCode() {
276: return isoCode.hashCode();
277: }
278:
279: /**
280: * Return true if rhs is a Currency instance,
281: * is non-null, and has the same currency code.
282: * @stable ICU 2.2
283: */
284: public boolean equals(Object rhs) {
285: if (rhs == null)
286: return false;
287: if (rhs == this )
288: return true;
289: try {
290: Currency c = (Currency) rhs;
291: return isoCode.equals(c.isoCode);
292: } catch (ClassCastException e) {
293: return false;
294: }
295: }
296:
297: /**
298: * Returns the ISO 4217 3-letter code for this currency object.
299: * @stable ICU 2.2
300: */
301: public String getCurrencyCode() {
302: return isoCode;
303: }
304:
305: /**
306: * Convenience and compatibility override of getName that
307: * requests the symbol name.
308: * @see #getName
309: * @draft ICU 3.4
310: * @provisional This API might change or be removed in a future release.
311: */
312: public String getSymbol() {
313: return getSymbol(ULocale.getDefault());
314: }
315:
316: /**
317: * Convenience and compatibility override of getName that
318: * requests the symbol name.
319: * @param loc the Locale for the symbol
320: * @see #getName
321: * @draft ICU 3.4
322: * @provisional This API might change or be removed in a future release.
323: */
324: public String getSymbol(Locale loc) {
325: return getSymbol(ULocale.forLocale(loc));
326: }
327:
328: /**
329: * Convenience and compatibility override of getName that
330: * requests the symbol name.
331: * @param uloc the ULocale for the symbol
332: * @see #getName
333: * @draft ICU 3.4
334: * @provisional This API might change or be removed in a future release.
335: */
336: public String getSymbol(ULocale uloc) {
337: return getName(uloc, SYMBOL_NAME, new boolean[1]);
338: }
339:
340: /**
341: * Returns the display name for the given currency in the
342: * given locale. For example, the display name for the USD
343: * currency object in the en_US locale is "$".
344: * @param locale locale in which to display currency
345: * @param nameStyle selector for which kind of name to return
346: * @param isChoiceFormat fill-in; isChoiceFormat[0] is set to true
347: * if the returned value is a ChoiceFormat pattern; otherwise it
348: * is set to false
349: * @return display string for this currency. If the resource data
350: * contains no entry for this currency, then the ISO 4217 code is
351: * returned. If isChoiceFormat[0] is true, then the result is a
352: * ChoiceFormat pattern. Otherwise it is a static string.
353: * @draft ICU 3.2
354: * @provisional This API might change or be removed in a future release.
355: */
356: public String getName(Locale locale, int nameStyle,
357: boolean[] isChoiceFormat) {
358: return getName(ULocale.forLocale(locale), nameStyle,
359: isChoiceFormat);
360: }
361:
362: /**
363: * Returns the display name for the given currency in the
364: * given locale. For example, the display name for the USD
365: * currency object in the en_US locale is "$".
366: * @param locale locale in which to display currency
367: * @param nameStyle selector for which kind of name to return
368: * @param isChoiceFormat fill-in; isChoiceFormat[0] is set to true
369: * if the returned value is a ChoiceFormat pattern; otherwise it
370: * is set to false
371: * @return display string for this currency. If the resource data
372: * contains no entry for this currency, then the ISO 4217 code is
373: * returned. If isChoiceFormat[0] is true, then the result is a
374: * ChoiceFormat pattern. Otherwise it is a static string.
375: * @draft ICU 3.2
376: * @provisional This API might change or be removed in a future release.
377: */
378: public String getName(ULocale locale, int nameStyle,
379: boolean[] isChoiceFormat) {
380:
381: // Look up the Currencies resource for the given locale. The
382: // Currencies locale data looks like this:
383: //|en {
384: //| Currencies {
385: //| USD { "US$", "US Dollar" }
386: //| CHF { "Sw F", "Swiss Franc" }
387: //| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
388: //| //...
389: //| }
390: //|}
391:
392: if (nameStyle < 0 || nameStyle > 1) {
393: throw new IllegalArgumentException();
394: }
395:
396: String s = null;
397:
398: try {
399: ICUResourceBundle rb = (ICUResourceBundle) UResourceBundle
400: .getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,
401: locale);
402: ICUResourceBundle currencies = rb.get("Currencies");
403:
404: // Fetch resource with multi-level resource inheritance fallback
405: s = currencies.getWithFallback(isoCode)
406: .getString(nameStyle);
407: } catch (MissingResourceException e) {
408: //TODO what should be done here?
409: }
410:
411: // Determine if this is a ChoiceFormat pattern. One leading mark
412: // indicates a ChoiceFormat. Two indicates a static string that
413: // starts with a mark. In either case, the first mark is ignored,
414: // if present. Marks in the rest of the string have no special
415: // meaning.
416: isChoiceFormat[0] = false;
417: if (s != null) {
418: int i = 0;
419: while (i < s.length() && s.charAt(i) == '=' && i < 2) {
420: ++i;
421: }
422: isChoiceFormat[0] = (i == 1);
423: if (i != 0) {
424: // Skip over first mark
425: s = s.substring(1);
426: }
427: return s;
428: }
429:
430: // If we fail to find a match, use the ISO 4217 code
431: return isoCode;
432: }
433:
434: /**
435: * Attempt to parse the given string as a currency, either as a
436: * display name in the given locale, or as a 3-letter ISO 4217
437: * code. If multiple display names match, then the longest one is
438: * selected. If both a display name and a 3-letter ISO code
439: * match, then the display name is preferred, unless it's length
440: * is less than 3.
441: *
442: * @param locale the locale of the display names to match
443: * @param text the text to parse
444: * @param pos input-output position; on input, the position within
445: * text to match; must have 0 <= pos.getIndex() < text.length();
446: * on output, the position after the last matched character. If
447: * the parse fails, the position in unchanged upon output.
448: * @return the ISO 4217 code, as a string, of the best match, or
449: * null if there is no match
450: *
451: * @internal
452: * @deprecated This API is ICU internal only.
453: */
454: public static String parse(ULocale locale, String text,
455: ParsePosition pos) {
456:
457: // TODO: There is a slight problem with the pseudo-multi-level
458: // fallback implemented here. More-specific locales don't
459: // properly shield duplicate entries in less-specific locales.
460: // This problem will go away when real multi-level fallback is
461: // implemented. We could also fix this by recording (in a
462: // hash) which codes are used at each level of fallback, but
463: // this doesn't seem warranted.
464:
465: int start = pos.getIndex();
466: String fragment = text.substring(start);
467:
468: String iso = null;
469: int max = 0;
470:
471: // Look up the Currencies resource for the given locale. The
472: // Currencies locale data looks like this:
473: //|en {
474: //| Currencies {
475: //| USD { "US$", "US Dollar" }
476: //| CHF { "Sw F", "Swiss Franc" }
477: //| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
478: //| //...
479: //| }
480: //|}
481:
482: // In the future, resource bundles may implement multi-level
483: // fallback. That is, if a currency is not found in the en_US
484: // Currencies data, then the en Currencies data will be searched.
485: // Currently, if a Currencies datum exists in en_US and en, the
486: // en_US entry hides that in en.
487:
488: // We want multi-level fallback for this resource, so we implement
489: // it manually.
490:
491: // Multi-level resource inheritance fallback loop
492:
493: while (locale != null) {
494: ICUResourceBundle rb = (ICUResourceBundle) UResourceBundle
495: .getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,
496: locale);
497: // We can't cast this to String[][]; the cast has to happen later
498:
499: try {
500: ICUResourceBundle currencies = rb.get("Currencies");
501: // Do a linear search
502: for (int i = 0; i < currencies.getSize(); ++i) {
503: //String name = ((String[]) currencies[i][1])[0];
504: ICUResourceBundle item = currencies.get(i);
505: String name = item.getString(0);
506: if (name.length() < 1) {
507: // Ignore zero-length names -- later, change this
508: // when zero-length is used to mean something.
509: continue;
510: } else if (name.charAt(0) == '=') {
511: name = name.substring(1);
512: if (name.length() > 0 && name.charAt(0) != '=') {
513: ChoiceFormat choice = new ChoiceFormat(name);
514: // Number n =
515: choice.parse(text, pos);
516: int len = pos.getIndex() - start;
517: if (len > max) {
518: iso = item.getKey();
519: max = len;
520: }
521: pos.setIndex(start);
522: continue;
523: }
524: }
525: if (name.length() > max
526: && fragment.startsWith(name)) {
527: iso = item.getKey();
528: max = name.length();
529: }
530: }
531: } catch (MissingResourceException e) {
532: }
533:
534: locale = locale.getFallback();
535: }
536:
537: /*
538: 1. Look at the Currencies array from the locale
539: 1a. Iterate through it, and check each row to see if row[1] matches
540: 1a1. If row[1] is a pattern, use ChoiceFormat to attempt a parse
541: 1b. Upon a match, return the ISO code stored at row[0]
542: 2. If there is no match, fall back to "en" and try again
543: 3. If there is no match, fall back to root and try again
544: 4. If still no match, parse 3-letter ISO {this code is probably unchanged}.
545:
546: ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.getBundleInstance(UResourceBundle.ICU_BASE_NAME, locale);
547: ICUResourceBundle currencies = rb.get("Currencies");
548: */
549: // If display name parse fails or if it matches fewer than 3
550: // characters, try to parse 3-letter ISO. Do this after the
551: // display name processing so 3-letter display names are
552: // preferred. Consider /[A-Z]{3}/ to be valid ISO, and parse
553: // it manually--UnicodeSet/regex are too slow and heavy.
554: if (max < 3 && (text.length() - start) >= 3) {
555: boolean valid = true;
556: for (int k = 0; k < 3; ++k) {
557: char ch = text.charAt(start + k); // 16-bit ok
558: if (ch < 'A' || ch > 'Z') {
559: valid = false;
560: break;
561: }
562: }
563: if (valid) {
564: iso = text.substring(start, start + 3);
565: max = 3;
566: }
567: }
568:
569: pos.setIndex(start + max);
570: return iso;
571: }
572:
573: /**
574: * Returns the number of the number of fraction digits that should
575: * be displayed for this currency.
576: * @return a non-negative number of fraction digits to be
577: * displayed
578: * @stable ICU 2.2
579: */
580: public int getDefaultFractionDigits() {
581: return (findData())[0];
582: }
583:
584: /**
585: * Returns the rounding increment for this currency, or 0.0 if no
586: * rounding is done by this currency.
587: * @return the non-negative rounding increment, or 0.0 if none
588: * @stable ICU 2.2
589: */
590: public double getRoundingIncrement() {
591: int[] data = findData();
592:
593: int data1 = data[1]; // rounding increment
594:
595: // If there is no rounding return 0.0 to indicate no rounding.
596: // This is the high-runner case, by far.
597: if (data1 == 0) {
598: return 0.0;
599: }
600:
601: int data0 = data[0]; // fraction digits
602:
603: // If the meta data is invalid, return 0.0 to indicate no rounding.
604: if (data0 < 0 || data0 >= POW10.length) {
605: return 0.0;
606: }
607:
608: // Return data[1] / 10^(data[0]). The only actual rounding data,
609: // as of this writing, is CHF { 2, 25 }.
610: return (double) data1 / POW10[data0];
611: }
612:
613: /**
614: * Returns the ISO 4217 code for this currency.
615: * @stable ICU 2.2
616: */
617: public String toString() {
618: return isoCode;
619: }
620:
621: /**
622: * Constructs a currency object for the given ISO 4217 3-letter
623: * code. This constructor assumes that the code is valid.
624: *
625: * @param theISOCode The iso code used to construct the currency.
626: * @draft ICU 3.4
627: * @provisional This API might change or be removed in a future release.
628: */
629: protected Currency(String theISOCode) {
630: isoCode = theISOCode;
631: }
632:
633: /**
634: * Internal function to look up currency data. Result is an array of
635: * two Integers. The first is the fraction digits. The second is the
636: * rounding increment, or 0 if none. The rounding increment is in
637: * units of 10^(-fraction_digits).
638: */
639: private int[] findData() {
640:
641: try {
642: // Get CurrencyMeta resource out of root locale file. [This may
643: // move out of the root locale file later; if it does, update this
644: // code.]
645: ICUResourceBundle root = (ICUResourceBundle) ICUResourceBundle
646: .getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,
647: "CurrencyData",
648: ICUResourceBundle.ICU_DATA_CLASS_LOADER);
649: ICUResourceBundle currencyMeta = root.get("CurrencyMeta");
650:
651: //Integer[] i = null;
652: //int defaultPos = -1;
653: int[] i = currencyMeta.get(isoCode).getIntVector();
654:
655: // Do a linear search for isoCode. At the same time,
656: // record the position of the DEFAULT meta data. If the
657: // meta data becomes large, make this faster.
658: /*for (int j=0; j<currencyMeta.length; ++j) {
659: Object[] row = currencyMeta[j];
660: String s = (String) row[0];
661: int c = isoCode.compareToIgnoreCase(s);
662: if (c == 0) {
663: i = (Integer[]) row[1];
664: break;
665: }
666: if ("DEFAULT".equalsIgnoreCase(s)) {
667: defaultPos = j;
668: }
669: if (c < 0 && defaultPos >= 0) {
670: break;
671: }
672: }
673: */
674: if (i == null) {
675: i = currencyMeta.get("DEFAULT").getIntVector();
676: }
677:
678: if (i != null && i.length >= 2) {
679: return i;
680: }
681: } catch (MissingResourceException e) {
682: }
683:
684: // Config/build error; return hard-coded defaults
685: return LAST_RESORT_DATA;
686: }
687:
688: // Default currency meta data of last resort. We try to use the
689: // defaults encoded in the meta data resource bundle. If there is a
690: // configuration/build error and these are not available, we use these
691: // hard-coded defaults (which should be identical).
692: private static final int[] LAST_RESORT_DATA = new int[] { 2, 0 };
693:
694: // POW10[i] = 10^i
695: private static final int[] POW10 = { 1, 10, 100, 1000, 10000,
696: 100000, 1000000, 10000000, 100000000, 1000000000 };
697:
698: // -------- BEGIN ULocale boilerplate --------
699:
700: /**
701: * Return the locale that was used to create this object, or null.
702: * This may may differ from the locale requested at the time of
703: * this object's creation. For example, if an object is created
704: * for locale <tt>en_US_CALIFORNIA</tt>, the actual data may be
705: * drawn from <tt>en</tt> (the <i>actual</i> locale), and
706: * <tt>en_US</tt> may be the most specific locale that exists (the
707: * <i>valid</i> locale).
708: *
709: * <p>Note: This method will be obsoleted. The implementation is
710: * no longer locale-specific and so there is no longer a valid or
711: * actual locale associated with the Currency object. Until
712: * it is removed, this method will return the root locale.
713: * @param type type of information requested, either {@link
714: * com.ibm.icu.util.ULocale#VALID_LOCALE} or {@link
715: * com.ibm.icu.util.ULocale#ACTUAL_LOCALE}.
716: * @return the information specified by <i>type</i>, or null if
717: * this object was not constructed from locale data.
718: * @see com.ibm.icu.util.ULocale
719: * @see com.ibm.icu.util.ULocale#VALID_LOCALE
720: * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE
721: * @obsolete ICU 3.2 to be removed
722: * @deprecated This API is obsolete.
723: */
724: public final ULocale getLocale(ULocale.Type type) {
725: return ULocale.ROOT;
726: }
727:
728: /**
729: * Set information about the locales that were used to create this
730: * object. If the object was not constructed from locale data,
731: * both arguments should be set to null. Otherwise, neither
732: * should be null. The actual locale must be at the same level or
733: * less specific than the valid locale. This method is intended
734: * for use by factories or other entities that create objects of
735: * this class.
736: * @param valid the most specific locale containing any resource
737: * data, or null
738: * @param actual the locale containing data used to construct this
739: * object, or null
740: * @see com.ibm.icu.util.ULocale
741: * @see com.ibm.icu.util.ULocale#VALID_LOCALE
742: * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE
743: * @internal
744: * @deprecated This API is ICU internal only.
745: */
746: final void setLocale(ULocale valid, ULocale actual) {
747: // Change the following to an assertion later
748: if ((valid == null) != (actual == null)) {
749: ///CLOVER:OFF
750: throw new IllegalArgumentException();
751: ///CLOVER:ON
752: }
753: // Another check we could do is that the actual locale is at
754: // the same level or less specific than the valid locale.
755: this .validLocale = valid;
756: this .actualLocale = actual;
757: }
758:
759: /**
760: * The most specific locale containing any resource data, or null.
761: * @see com.ibm.icu.util.ULocale
762: * @internal
763: * @deprecated This API is ICU internal only.
764: */
765: private ULocale validLocale;
766:
767: /**
768: * The locale containing data used to construct this object, or
769: * null.
770: * @see com.ibm.icu.util.ULocale
771: * @internal
772: * @deprecated This API is ICU internal only.
773: */
774: private ULocale actualLocale;
775:
776: // -------- END ULocale boilerplate --------
777: }
778:
779: //eof
|