1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /** 4 ******************************************************************************* 5 * Copyright (C) 2001-2013, International Business Machines Corporation and * 6 * others. All Rights Reserved. * 7 ******************************************************************************* 8 */ 9 package com.ibm.icu.dev.test.util; 10 11 import java.text.Collator; 12 import java.util.Arrays; 13 import java.util.Collections; 14 import java.util.Comparator; 15 import java.util.EventListener; 16 import java.util.HashMap; 17 import java.util.HashSet; 18 import java.util.Iterator; 19 import java.util.List; 20 import java.util.Map; 21 import java.util.Map.Entry; 22 import java.util.Set; 23 import java.util.SortedMap; 24 25 import org.junit.Test; 26 import org.junit.runner.RunWith; 27 import org.junit.runners.JUnit4; 28 29 import com.ibm.icu.dev.test.TestFmwk; 30 import com.ibm.icu.impl.ICULocaleService; 31 import com.ibm.icu.impl.ICULocaleService.ICUResourceBundleFactory; 32 import com.ibm.icu.impl.ICULocaleService.LocaleKey; 33 import com.ibm.icu.impl.ICULocaleService.LocaleKeyFactory; 34 import com.ibm.icu.impl.ICUNotifier; 35 import com.ibm.icu.impl.ICURWLock; 36 import com.ibm.icu.impl.ICUResourceBundle; 37 import com.ibm.icu.impl.ICUService; 38 import com.ibm.icu.impl.ICUService.Factory; 39 import com.ibm.icu.impl.ICUService.Key; 40 import com.ibm.icu.impl.ICUService.ServiceListener; 41 import com.ibm.icu.impl.ICUService.SimpleFactory; 42 import com.ibm.icu.impl.LocaleUtility; 43 import com.ibm.icu.util.ULocale; 44 45 @RunWith(JUnit4.class) 46 public class ICUServiceTest extends TestFmwk 47 { 48 private String lrmsg(String message, Object lhs, Object rhs) { 49 return message + " lhs: " + lhs + " rhs: " + rhs; 50 } 51 52 public void confirmBoolean(String message, boolean val) { 53 msg(message, val ? LOG : ERR, !val, true); 54 } 55 56 public void confirmEqual(String message, Object lhs, Object rhs) { 57 msg(lrmsg(message, lhs, rhs), (lhs == null ? rhs == null : lhs.equals(rhs)) ? LOG : ERR, true, true); 58 } 59 60 public void confirmIdentical(String message, Object lhs, Object rhs) { 61 msg(lrmsg(message, lhs, rhs), lhs == rhs ? LOG : ERR, true, true); 62 } 63 64 public void confirmIdentical(String message, int lhs, int rhs) { 65 msg(message + " lhs: " + lhs + " rhs: " + rhs, lhs == rhs ? LOG : ERR, true, true); 66 } 67 68 /** 69 * Convenience override of getDisplayNames(ULocale, Comparator, String) that 70 * uses the current default ULocale as the locale, the default collator for 71 * the locale as the comparator to sort the display names, and null for 72 * the matchID. 73 */ 74 public SortedMap getDisplayNames(ICUService service) { 75 ULocale locale = ULocale.getDefault(); 76 Collator col = Collator.getInstance(locale.toLocale()); 77 return service.getDisplayNames(locale, col, null); 78 } 79 80 /** 81 * Convenience override of getDisplayNames(ULocale, Comparator, String) that 82 * uses the default collator for the locale as the comparator to 83 * sort the display names, and null for the matchID. 84 */ 85 public SortedMap getDisplayNames(ICUService service, ULocale locale) { 86 Collator col = Collator.getInstance(locale.toLocale()); 87 return service.getDisplayNames(locale, col, null); 88 } 89 /** 90 * Convenience override of getDisplayNames(ULocale, Comparator, String) that 91 * uses the default collator for the locale as the comparator to 92 * sort the display names. 93 */ 94 public SortedMap getDisplayNames(ICUService service, ULocale locale, String matchID) { 95 Collator col = Collator.getInstance(locale.toLocale()); 96 return service.getDisplayNames(locale, col, matchID); 97 } 98 99 // use locale keys 100 static final class TestService extends ICUService { 101 public TestService() { 102 super("Test Service"); 103 } 104 105 @Override 106 public Key createKey(String id) { 107 return LocaleKey.createWithCanonicalFallback(id, null); // no fallback locale 108 } 109 } 110 111 @Test 112 public void TestAPI() { 113 // create a service using locale keys, 114 ICUService service = new TestService(); 115 116 logln("service name:" + service.getName()); 117 118 // register an object with one locale, 119 // search for an object with a more specific locale 120 // should return the original object 121 Integer singleton0 = new Integer(0); 122 service.registerObject(singleton0, "en_US"); 123 Object result = service.get("en_US_FOO"); 124 confirmIdentical("1) en_US_FOO -> en_US", result, singleton0); 125 126 // register a new object with the more specific locale 127 // search for an object with that locale 128 // should return the new object 129 Integer singleton1 = new Integer(1); 130 service.registerObject(singleton1, "en_US_FOO"); 131 result = service.get("en_US_FOO"); 132 confirmIdentical("2) en_US_FOO -> en_US_FOO", result, singleton1); 133 134 // search for an object that falls back to the first registered locale 135 result = service.get("en_US_BAR"); 136 confirmIdentical("3) en_US_BAR -> en_US", result, singleton0); 137 138 // get a list of the factories, should be two 139 List factories = service.factories(); 140 confirmIdentical("4) factory size", factories.size(), 2); 141 142 // register a new object with yet another locale 143 // original factory list is unchanged 144 Integer singleton2 = new Integer(2); 145 service.registerObject(singleton2, "en"); 146 confirmIdentical("5) factory size", factories.size(), 2); 147 148 // search for an object with the new locale 149 // stack of factories is now en, en_US_FOO, en_US 150 // search for en_US should still find en_US object 151 result = service.get("en_US_BAR"); 152 confirmIdentical("6) en_US_BAR -> en_US", result, singleton0); 153 154 // register a new object with an old id, should hide earlier factory using this id, but leave it there 155 Integer singleton3 = new Integer(3); 156 service.registerObject(singleton3, "en_US"); 157 factories = service.factories(); 158 confirmIdentical("9) factory size", factories.size(), 4); 159 160 // should get data from that new factory 161 result = service.get("en_US_BAR"); 162 confirmIdentical("10) en_US_BAR -> (3)", result, singleton3); 163 164 // remove new factory 165 // should have fewer factories again 166 service.unregisterFactory((Factory)factories.get(0)); 167 factories = service.factories(); 168 confirmIdentical("11) factory size", factories.size(), 3); 169 170 // should get original data again after remove factory 171 result = service.get("en_US_BAR"); 172 confirmIdentical("12) en_US_BAR -> 0", result, singleton0); 173 174 // shouldn't find unregistered ids 175 result = service.get("foo"); 176 confirmIdentical("13) foo -> null", result, null); 177 178 // should find non-canonical strings 179 String[] resultID = new String[1]; 180 result = service.get("EN_us_fOo", resultID); 181 confirmEqual("14) find non-canonical", resultID[0], "en_US_FOO"); 182 183 // should be able to register non-canonical strings and get them canonicalized 184 service.registerObject(singleton3, "eN_ca_dUde"); 185 result = service.get("En_Ca_DuDe", resultID); 186 confirmEqual("15) register non-canonical", resultID[0], "en_CA_DUDE"); 187 188 // should be able to register invisible factories, these will not 189 // be visible by default, but if you know the secret password you 190 // can still access these services... 191 Integer singleton4 = new Integer(4); 192 service.registerObject(singleton4, "en_US_BAR", false); 193 result = service.get("en_US_BAR"); 194 confirmIdentical("17) get invisible", result, singleton4); 195 196 // should not be able to locate invisible services 197 Set ids = service.getVisibleIDs(); 198 confirmBoolean("18) find invisible", !ids.contains("en_US_BAR")); 199 200 service.reset(); 201 // an anonymous factory than handles all ids 202 { 203 Factory factory = new Factory() { 204 @Override 205 public Object create(Key key, ICUService unusedService) { 206 return new ULocale(key.currentID()); 207 } 208 209 @Override 210 public void updateVisibleIDs(Map unusedResult) { 211 } 212 213 @Override 214 public String getDisplayName(String id, ULocale l) { 215 return null; 216 } 217 }; 218 service.registerFactory(factory); 219 220 // anonymous factory will still handle the id 221 result = service.get(ULocale.US.toString()); 222 confirmEqual("21) locale", result, ULocale.US); 223 224 // still normalizes id 225 result = service.get("EN_US_BAR"); 226 confirmEqual("22) locale", result, new ULocale("en_US_BAR")); 227 228 // we can override for particular ids 229 service.registerObject(singleton3, "en_US_BAR"); 230 result = service.get("en_US_BAR"); 231 confirmIdentical("23) override super", result, singleton3); 232 233 } 234 235 // empty service should not recognize anything 236 service.reset(); 237 result = service.get("en_US"); 238 confirmIdentical("24) empty", result, null); 239 240 // create a custom multiple key factory 241 { 242 String[] xids = { "en_US_VALLEY_GIRL", 243 "en_US_VALLEY_BOY", 244 "en_US_SURFER_GAL", 245 "en_US_SURFER_DUDE" 246 }; 247 service.registerFactory(new TestLocaleKeyFactory(xids, "Later")); 248 } 249 250 // iterate over the visual ids returned by the multiple factory 251 { 252 Set vids = service.getVisibleIDs(); 253 Iterator iter = vids.iterator(); 254 int count = 0; 255 while (iter.hasNext()) { 256 ++count; 257 String id = (String)iter.next(); 258 logln(" " + id + " --> " + service.get(id)); 259 } 260 // four visible ids 261 confirmIdentical("25) visible ids", count, 4); 262 } 263 264 // iterate over the display names 265 { 266 Map dids = getDisplayNames(service, ULocale.GERMANY); 267 Iterator iter = dids.entrySet().iterator(); 268 int count = 0; 269 while (iter.hasNext()) { 270 ++count; 271 Entry e = (Entry)iter.next(); 272 logln(" " + e.getKey() + " -- > " + e.getValue()); 273 } 274 // four display names, in german 275 confirmIdentical("26) display names", count, 4); 276 } 277 278 // no valid display name 279 confirmIdentical("27) get display name", service.getDisplayName("en_US_VALLEY_GEEK"), null); 280 281 { 282 String name = service.getDisplayName("en_US_SURFER_DUDE", ULocale.US); 283 confirmEqual("28) get display name", name, "English (United States, SURFER_DUDE)"); 284 } 285 286 // register another multiple factory 287 { 288 String[] xids = { 289 "en_US_SURFER", "en_US_SURFER_GAL", "en_US_SILICON", "en_US_SILICON_GEEK" 290 }; 291 service.registerFactory(new TestLocaleKeyFactory(xids, "Rad dude")); 292 } 293 294 // this time, we have seven display names 295 // Rad dude's surfer gal 'replaces' later's surfer gal 296 { 297 Map dids = getDisplayNames(service); 298 Iterator iter = dids.entrySet().iterator(); 299 int count = 0; 300 while (iter.hasNext()) { 301 ++count; 302 Entry e = (Entry)iter.next(); 303 logln(" " + e.getKey() + " --> " + e.getValue()); 304 } 305 // seven display names, in spanish 306 confirmIdentical("29) display names", count, 7); 307 } 308 309 // we should get the display name corresponding to the actual id 310 // returned by the id we used. 311 { 312 String[] actualID = new String[1]; 313 String id = "en_us_surfer_gal"; 314 String gal = (String)service.get(id, actualID); 315 if (gal != null) { 316 logln("actual id: " + actualID[0]); 317 String displayName = service.getDisplayName(actualID[0], ULocale.US); 318 logln("found actual: " + gal + " with display name: " + displayName); 319 confirmBoolean("30) found display name for actual", displayName != null); 320 321 displayName = service.getDisplayName(id, ULocale.US); 322 logln("found query: " + gal + " with display name: " + displayName); 323 // this is no longer a bug, we want to return display names for anything 324 // that a factory handles. since we handle it, we should return a display 325 // name. see jb3549 326 // confirmBoolean("31) found display name for query", displayName == null); 327 } else { 328 errln("30) service could not find entry for " + id); 329 } 330 331 // this should be handled by the 'dude' factory, since it overrides en_US_SURFER. 332 id = "en_US_SURFER_BOZO"; 333 String bozo = (String)service.get(id, actualID); 334 if (bozo != null) { 335 String displayName = service.getDisplayName(actualID[0], ULocale.US); 336 logln("found actual: " + bozo + " with display name: " + displayName); 337 confirmBoolean("32) found display name for actual", displayName != null); 338 339 displayName = service.getDisplayName(id, ULocale.US); 340 logln("found actual: " + bozo + " with display name: " + displayName); 341 // see above and jb3549 342 // confirmBoolean("33) found display name for query", displayName == null); 343 } else { 344 errln("32) service could not find entry for " + id); 345 } 346 347 confirmBoolean("34) is default ", !service.isDefault()); 348 } 349 350 /* 351 // disallow hiding for now 352 353 // hiding factory should obscure 'sublocales' 354 { 355 String[] xids = { 356 "en_US_VALLEY", "en_US_SILICON" 357 }; 358 service.registerFactory(new TestHidingFactory(xids, "hiding")); 359 } 360 361 { 362 Map dids = service.getDisplayNames(); 363 Iterator iter = dids.entrySet().iterator(); 364 int count = 0; 365 while (iter.hasNext()) { 366 ++count; 367 Entry e = (Entry)iter.next(); 368 logln(" " + e.getKey() + " -- > " + e.getValue()); 369 } 370 confirmIdentical("35) hiding factory", count, 5); 371 } 372 */ 373 374 { 375 Set xids = service.getVisibleIDs(); 376 Iterator iter = xids.iterator(); 377 while (iter.hasNext()) { 378 String xid = (String)iter.next(); 379 logln(xid + "? " + service.get(xid)); 380 } 381 382 logln("valleygirl? " + service.get("en_US_VALLEY_GIRL")); 383 logln("valleyboy? " + service.get("en_US_VALLEY_BOY")); 384 logln("valleydude? " + service.get("en_US_VALLEY_DUDE")); 385 logln("surfergirl? " + service.get("en_US_SURFER_GIRL")); 386 } 387 388 // resource bundle factory. 389 service.reset(); 390 service.registerFactory(new ICUResourceBundleFactory()); 391 392 // list all of the resources 393 { 394 logln("all visible ids: " + service.getVisibleIDs()); 395 /* 396 Set xids = service.getVisibleIDs(); 397 StringBuffer buf = new StringBuffer("{"); 398 boolean notfirst = false; 399 Iterator iter = xids.iterator(); 400 while (iter.hasNext()) { 401 String xid = (String)iter.next(); 402 if (notfirst) { 403 buf.append(", "); 404 } else { 405 notfirst = true; 406 } 407 buf.append(xid); 408 } 409 buf.append("}"); 410 logln(buf.toString()); 411 */ 412 } 413 414 // list only the resources for es, default locale 415 // since we're using the default Key, only "es" is matched 416 { 417 logln("visible ids for es locale: " + service.getVisibleIDs("es")); 418 } 419 420 // list only the spanish display names for es, spanish collation order 421 // since we're using the default Key, only "es" is matched 422 { 423 logln("display names: " + getDisplayNames(service, new ULocale("es"), "es")); 424 } 425 426 // list the display names in reverse order 427 { 428 logln("display names in reverse order: " + 429 service.getDisplayNames(ULocale.US, new Comparator() { 430 @Override 431 public int compare(Object lhs, Object rhs) { 432 return -String.CASE_INSENSITIVE_ORDER.compare((String)lhs, (String)rhs); 433 } 434 })); 435 } 436 437 // get all the display names of these resources 438 // this should be fast since the display names were cached. 439 { 440 logln("service display names for de_DE"); 441 Map names = getDisplayNames(service, new ULocale("de_DE")); 442 StringBuffer buf = new StringBuffer("{"); 443 Iterator iter = names.entrySet().iterator(); 444 while (iter.hasNext()) { 445 Entry e = (Entry)iter.next(); 446 String name = (String)e.getKey(); 447 String id = (String)e.getValue(); 448 buf.append("\n " + name + " --> " + id); 449 } 450 buf.append("\n}"); 451 logln(buf.toString()); 452 } 453 454 CalifornioLanguageFactory califactory = new CalifornioLanguageFactory(); 455 service.registerFactory(califactory); 456 // get all the display names of these resources 457 { 458 logln("californio language factory"); 459 StringBuffer buf = new StringBuffer("{"); 460 String[] idNames = { 461 CalifornioLanguageFactory.californio, 462 CalifornioLanguageFactory.valley, 463 CalifornioLanguageFactory.surfer, 464 CalifornioLanguageFactory.geek 465 }; 466 for (int i = 0; i < idNames.length; ++i) { 467 String idName = idNames[i]; 468 buf.append("\n --- " + idName + " ---"); 469 Map names = getDisplayNames(service, new ULocale(idName)); 470 Iterator iter = names.entrySet().iterator(); 471 while (iter.hasNext()) { 472 Entry e = (Entry)iter.next(); 473 String name = (String)e.getKey(); 474 String id = (String)e.getValue(); 475 buf.append("\n " + name + " --> " + id); 476 } 477 } 478 buf.append("\n}"); 479 logln(buf.toString()); 480 } 481 482 // test notification 483 // simple registration 484 { 485 logln("simple registration notification"); 486 ICULocaleService ls = new ICULocaleService(); 487 ServiceListener l1 = new ServiceListener() { 488 private int n; 489 @Override 490 public void serviceChanged(ICUService s) { 491 logln("listener 1 report " + n++ + " service changed: " + s); 492 } 493 }; 494 ls.addListener(l1); 495 ServiceListener l2 = new ServiceListener() { 496 private int n; 497 @Override 498 public void serviceChanged(ICUService s) { 499 logln("listener 2 report " + n++ + " service changed: " + s); 500 } 501 }; 502 ls.addListener(l2); 503 logln("registering foo... "); 504 ls.registerObject("Foo", "en_FOO"); 505 logln("registering bar... "); 506 ls.registerObject("Bar", "en_BAR"); 507 logln("getting foo..."); 508 logln((String)ls.get("en_FOO")); 509 logln("removing listener 2..."); 510 ls.removeListener(l2); 511 logln("registering baz..."); 512 ls.registerObject("Baz", "en_BAZ"); 513 logln("removing listener 1"); 514 ls.removeListener(l1); 515 logln("registering burp..."); 516 ls.registerObject("Burp", "en_BURP"); 517 518 // should only get one notification even if register multiple times 519 logln("... trying multiple registration"); 520 ls.addListener(l1); 521 ls.addListener(l1); 522 ls.addListener(l1); 523 ls.addListener(l2); 524 ls.registerObject("Foo", "en_FOO"); 525 logln("... registered foo"); 526 527 // since in a separate thread, we can callback and not deadlock 528 ServiceListener l3 = new ServiceListener() { 529 private int n; 530 @Override 531 public void serviceChanged(ICUService s) { 532 logln("listener 3 report " + n++ + " service changed..."); 533 if (s.get("en_BOINK") == null) { // don't recurse on ourselves!!! 534 logln("registering boink..."); 535 s.registerObject("boink", "en_BOINK"); 536 } 537 } 538 }; 539 ls.addListener(l3); 540 logln("registering boo..."); 541 ls.registerObject("Boo", "en_BOO"); 542 logln("...done"); 543 544 try { 545 Thread.sleep(100); 546 } 547 catch (InterruptedException e) { 548 } 549 } 550 } 551 552 static class TestLocaleKeyFactory extends LocaleKeyFactory { 553 protected final Set ids; 554 protected final String factoryID; 555 556 public TestLocaleKeyFactory(String[] ids, String factoryID) { 557 super(VISIBLE, factoryID); 558 559 this.ids = Collections.unmodifiableSet(new HashSet(Arrays.asList(ids))); 560 this.factoryID = factoryID + ": "; 561 } 562 563 @Override 564 protected Object handleCreate(ULocale loc, int kind, ICUService service) { 565 return factoryID + loc.toString(); 566 } 567 568 @Override 569 protected Set getSupportedIDs() { 570 return ids; 571 } 572 } 573 574 /* 575 // Disallow hiding for now since it causes gnarly problems, like 576 // how do you localize the hidden (but still exported) names. 577 578 static class TestHidingFactory implements ICUService.Factory { 579 protected final String[] ids; 580 protected final String factoryID; 581 582 public TestHidingFactory(String[] ids) { 583 this(ids, "Hiding"); 584 } 585 586 public TestHidingFactory(String[] ids, String factoryID) { 587 this.ids = (String[])ids.clone(); 588 589 if (factoryID == null || factoryID.length() == 0) { 590 this.factoryID = ""; 591 } else { 592 this.factoryID = factoryID + ": "; 593 } 594 } 595 596 public Object create(Key key, ICUService service) { 597 for (int i = 0; i < ids.length; ++i) { 598 if (LocaleUtility.isFallbackOf(ids[i], key.currentID())) { 599 return factoryID + key.canonicalID(); 600 } 601 } 602 return null; 603 } 604 605 public void updateVisibleIDs(Map result) { 606 for (int i = 0; i < ids.length; ++i) { 607 String id = ids[i]; 608 Iterator iter = result.keySet().iterator(); 609 while (iter.hasNext()) { 610 if (LocaleUtility.isFallbackOf(id, (String)iter.next())) { 611 iter.remove(); 612 } 613 } 614 result.put(id, this); 615 } 616 } 617 618 public String getDisplayName(String id, ULocale locale) { 619 return factoryID + new ULocale(id).getDisplayName(locale); 620 } 621 } 622 */ 623 624 static class CalifornioLanguageFactory extends ICUResourceBundleFactory { 625 public static String californio = "en_US_CA"; 626 public static String valley = californio + "_VALLEY"; 627 public static String surfer = californio + "_SURFER"; 628 public static String geek = californio + "_GEEK"; 629 public static Set supportedIDs; 630 static { 631 HashSet result = new HashSet(); 632 result.addAll(ICUResourceBundle.getAvailableLocaleNameSet()); 633 result.add(californio); 634 result.add(valley); 635 result.add(surfer); 636 result.add(geek); 637 supportedIDs = Collections.unmodifiableSet(result); 638 } 639 640 @Override 641 public Set getSupportedIDs() { 642 return supportedIDs; 643 } 644 645 @Override 646 public String getDisplayName(String id, ULocale locale) { 647 String prefix = ""; 648 String suffix = ""; 649 String ls = locale.toString(); 650 if (LocaleUtility.isFallbackOf(californio, ls)) { 651 if (ls.equalsIgnoreCase(valley)) { 652 prefix = "Like, you know, it's so totally "; 653 } else if (ls.equalsIgnoreCase(surfer)) { 654 prefix = "Dude, its "; 655 } else if (ls.equalsIgnoreCase(geek)) { 656 prefix = "I'd estimate it's approximately "; 657 } else { 658 prefix = "Huh? Maybe "; 659 } 660 } 661 if (LocaleUtility.isFallbackOf(californio, id)) { 662 if (id.equalsIgnoreCase(valley)) { 663 suffix = "like the Valley, you know? Let's go to the mall!"; 664 } else if (id.equalsIgnoreCase(surfer)) { 665 suffix = "time to hit those gnarly waves, Dude!!!"; 666 } else if (id.equalsIgnoreCase(geek)) { 667 suffix = "all systems go. T-Minus 9, 8, 7..."; 668 } else { 669 suffix = "No Habla Englais"; 670 } 671 } else { 672 suffix = super.getDisplayName(id, locale); 673 } 674 675 return prefix + suffix; 676 } 677 } 678 679 @Test 680 public void TestLocale() { 681 ICULocaleService service = new ICULocaleService("test locale"); 682 service.registerObject("root", ULocale.ROOT); 683 service.registerObject("german", "de"); 684 service.registerObject("german_Germany", ULocale.GERMANY); 685 service.registerObject("japanese", "ja"); 686 service.registerObject("japanese_Japan", ULocale.JAPAN); 687 688 Object target = service.get("de_US"); 689 confirmEqual("test de_US", "german", target); 690 691 ULocale de = new ULocale("de"); 692 ULocale de_US = new ULocale("de_US"); 693 694 target = service.get(de_US); 695 confirmEqual("test de_US 2", "german", target); 696 697 target = service.get(de_US, LocaleKey.KIND_ANY); 698 confirmEqual("test de_US 3", "german", target); 699 700 target = service.get(de_US, 1234); 701 confirmEqual("test de_US 4", "german", target); 702 703 ULocale[] actualReturn = new ULocale[1]; 704 target = service.get(de_US, actualReturn); 705 confirmEqual("test de_US 5", "german", target); 706 confirmEqual("test de_US 6", actualReturn[0], de); 707 708 actualReturn[0] = null; 709 target = service.get(de_US, LocaleKey.KIND_ANY, actualReturn); 710 confirmEqual("test de_US 7", actualReturn[0], de); 711 712 actualReturn[0] = null; 713 target = service.get(de_US, 1234, actualReturn); 714 confirmEqual("test de_US 8", "german", target); 715 confirmEqual("test de_US 9", actualReturn[0], de); 716 717 service.registerObject("one/de_US", de_US, 1); 718 service.registerObject("two/de_US", de_US, 2); 719 720 target = service.get(de_US, 1); 721 confirmEqual("test de_US kind 1", "one/de_US", target); 722 723 target = service.get(de_US, 2); 724 confirmEqual("test de_US kind 2", "two/de_US", target); 725 726 target = service.get(de_US); 727 confirmEqual("test de_US kind 3", "german", target); 728 729 LocaleKey lkey = LocaleKey.createWithCanonicalFallback("en", null, 1234); 730 logln("lkey prefix: " + lkey.prefix()); 731 logln("lkey descriptor: " + lkey.currentDescriptor()); 732 logln("lkey current locale: " + lkey.currentLocale()); 733 734 lkey.fallback(); 735 logln("lkey descriptor 2: " + lkey.currentDescriptor()); 736 737 lkey.fallback(); 738 logln("lkey descriptor 3: " + lkey.currentDescriptor()); 739 740 target = service.get("za_PPP"); 741 confirmEqual("test zappp", "root", target); 742 743 ULocale loc = ULocale.getDefault(); 744 ULocale.setDefault(ULocale.JAPANESE); 745 target = service.get("za_PPP"); 746 confirmEqual("test with ja locale", "japanese", target); 747 748 Set ids = service.getVisibleIDs(); 749 for (Iterator iter = ids.iterator(); iter.hasNext();) { 750 logln("id: " + iter.next()); 751 } 752 753 ULocale.setDefault(loc); 754 ids = service.getVisibleIDs(); 755 for (Iterator iter = ids.iterator(); iter.hasNext();) { 756 logln("id: " + iter.next()); 757 } 758 759 target = service.get("za_PPP"); 760 confirmEqual("test with en locale", "root", target); 761 762 ULocale[] locales = service.getAvailableULocales(); 763 confirmIdentical("test available locales", locales.length, 6); 764 logln("locales: "); 765 for (int i = 0; i < locales.length; ++i) { 766 log("\n [" + i + "] " + locales[i]); 767 } 768 logln(" "); 769 770 service.registerFactory(new ICUResourceBundleFactory()); 771 target = service.get(ULocale.JAPAN); 772 773 { 774 int n = 0; 775 List factories = service.factories(); 776 Iterator iter = factories.iterator(); 777 while (iter.hasNext()) { 778 logln("[" + n++ + "] " + iter.next()); 779 } 780 } 781 782 // list only the english display names for es, in reverse order 783 // since we're using locale keys, we should get all and only the es locales 784 // hmmm, the default toString function doesn't print in sorted order for TreeMap 785 { 786 SortedMap map = service.getDisplayNames(ULocale.US, 787 new Comparator() { 788 @Override 789 public int compare(Object lhs, Object rhs) { 790 return -String.CASE_INSENSITIVE_ORDER.compare((String)lhs, (String)rhs); 791 } 792 }, 793 "es"); 794 795 logln("es display names in reverse order " + map); 796 } 797 } 798 799 @Test 800 public void TestWrapFactory() { 801 final String greeting = "Hello There"; 802 final String greetingID = "greeting"; 803 804 ICUService service = new ICUService("wrap"); 805 service.registerObject(greeting, greetingID); 806 807 logln("test one: " + service.get(greetingID)); 808 809 class WrapFactory implements Factory { 810 @Override 811 public Object create(Key key, ICUService serviceArg) { 812 if (key.currentID().equals(greetingID)) { 813 Object previous = serviceArg.getKey(key, null, this); 814 return "A different greeting: \"" + previous + "\""; 815 } 816 return null; 817 } 818 819 @Override 820 public void updateVisibleIDs(Map result) { 821 result.put("greeting", this); 822 } 823 824 @Override 825 public String getDisplayName(String id, ULocale locale) { 826 return "wrap '" + id + "'"; 827 } 828 } 829 service.registerFactory(new WrapFactory()); 830 831 confirmEqual("wrap test: ", service.get(greetingID), "A different greeting: \"" + greeting + "\""); 832 } 833 834 // misc coverage tests 835 @Test 836 public void TestCoverage() { 837 // Key 838 Key key = new Key("foobar"); 839 logln("ID: " + key.id()); 840 logln("canonicalID: " + key.canonicalID()); 841 logln("currentID: " + key.currentID()); 842 logln("has fallback: " + key.fallback()); 843 844 // SimpleFactory 845 Object obj = new Object(); 846 SimpleFactory sf = new SimpleFactory(obj, "object"); 847 try { 848 sf = new SimpleFactory(null, null); 849 errln("didn't throw exception"); 850 } 851 catch (IllegalArgumentException e) { 852 logln("OK: " + e.getMessage()); 853 } 854 catch (Exception e) { 855 errln("threw wrong exception" + e); 856 } 857 logln(sf.getDisplayName("object", null)); 858 859 // ICUService 860 ICUService service = new ICUService(); 861 service.registerFactory(sf); 862 863 try { 864 service.get(null, null); 865 errln("didn't throw exception"); 866 } 867 catch (NullPointerException e) { 868 logln("OK: " + e.getMessage()); 869 } 870 /* 871 catch (Exception e) { 872 errln("threw wrong exception" + e); 873 } 874 */ 875 try { 876 service.registerFactory(null); 877 errln("didn't throw exception"); 878 } 879 catch (NullPointerException e) { 880 logln("OK: " + e.getMessage()); 881 } 882 catch (Exception e) { 883 errln("threw wrong exception" + e); 884 } 885 886 try { 887 service.unregisterFactory(null); 888 errln("didn't throw exception"); 889 } 890 catch (NullPointerException e) { 891 logln("OK: " + e.getMessage()); 892 } 893 catch (Exception e) { 894 errln("threw wrong exception" + e); 895 } 896 897 logln("object is: " + service.get("object")); 898 899 logln("stats: " + service.stats()); 900 901 // ICURWLock 902 903 ICURWLock rwlock = new ICURWLock(); 904 rwlock.resetStats(); 905 906 rwlock.acquireRead(); 907 rwlock.releaseRead(); 908 909 rwlock.acquireWrite(); 910 rwlock.releaseWrite(); 911 logln("stats: " + rwlock.getStats()); 912 logln("stats: " + rwlock.clearStats()); 913 rwlock.acquireRead(); 914 rwlock.releaseRead(); 915 rwlock.acquireWrite(); 916 rwlock.releaseWrite(); 917 logln("stats: " + rwlock.getStats()); 918 919 try { 920 rwlock.releaseRead(); 921 errln("no error thrown"); 922 } 923 catch (Exception e) { 924 logln("OK: " + e.getMessage()); 925 } 926 927 try { 928 rwlock.releaseWrite(); 929 errln("no error thrown"); 930 } 931 catch (Exception e) { 932 logln("OK: " + e.getMessage()); 933 } 934 935 // ICULocaleService 936 937 // LocaleKey 938 939 // LocaleKey lkey = LocaleKey.create("en_US", "ja_JP"); 940 // lkey = LocaleKey.create(null, null); 941 LocaleKey lkey = LocaleKey.createWithCanonicalFallback("en_US", "ja_JP"); 942 logln("lkey: " + lkey); 943 944 lkey = LocaleKey.createWithCanonicalFallback(null, null); 945 logln("lkey from null,null: " + lkey); 946 947 // LocaleKeyFactory 948 LocaleKeyFactory lkf = new LKFSubclass(false); 949 logln("lkf: " + lkf); 950 logln("obj: " + lkf.create(lkey, null)); 951 logln(lkf.getDisplayName("foo", null)); 952 logln(lkf.getDisplayName("bar", null)); 953 lkf.updateVisibleIDs(new HashMap()); 954 955 LocaleKeyFactory invisibleLKF = new LKFSubclass(false); 956 logln("obj: " + invisibleLKF.create(lkey, null)); 957 logln(invisibleLKF.getDisplayName("foo", null)); 958 logln(invisibleLKF.getDisplayName("bar", null)); 959 invisibleLKF.updateVisibleIDs(new HashMap()); 960 961 // ResourceBundleFactory 962 ICUResourceBundleFactory rbf = new ICUResourceBundleFactory(); 963 logln("RB: " + rbf.create(lkey, null)); 964 965 // ICUNotifier 966 ICUNotifier nf = new ICUNSubclass(); 967 try { 968 nf.addListener(null); 969 errln("added null listener"); 970 } 971 catch (NullPointerException e) { 972 logln(e.getMessage()); 973 } 974 catch (Exception e) { 975 errln("got wrong exception"); 976 } 977 978 try { 979 nf.addListener(new WrongListener()); 980 errln("added wrong listener"); 981 } 982 catch (IllegalStateException e) { 983 logln(e.getMessage()); 984 } 985 catch (Exception e) { 986 errln("got wrong exception"); 987 } 988 989 try { 990 nf.removeListener(null); 991 errln("removed null listener"); 992 } 993 catch (NullPointerException e) { 994 logln(e.getMessage()); 995 } 996 catch (Exception e) { 997 errln("got wrong exception"); 998 } 999 1000 nf.removeListener(new MyListener()); 1001 nf.notifyChanged(); 1002 nf.addListener(new MyListener()); 1003 nf.removeListener(new MyListener()); 1004 } 1005 1006 static class MyListener implements EventListener { 1007 } 1008 1009 static class WrongListener implements EventListener { 1010 } 1011 1012 static class ICUNSubclass extends ICUNotifier { 1013 @Override 1014 public boolean acceptsListener(EventListener l) { 1015 return l instanceof MyListener; 1016 } 1017 1018 // not used, just needed to implement abstract base 1019 @Override 1020 public void notifyListener(EventListener l) { 1021 } 1022 } 1023 1024 static class LKFSubclass extends LocaleKeyFactory { 1025 LKFSubclass(boolean visible) { 1026 super(visible ? VISIBLE : INVISIBLE); 1027 } 1028 1029 @Override 1030 protected Set getSupportedIDs() { 1031 return Collections.EMPTY_SET; 1032 } 1033 } 1034 } 1035