1 /** 2 ******************************************************************************* 3 * Copyright (C) 2001-2013, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 */ 7 package com.ibm.icu.dev.test.util; 8 9 import java.text.Collator; 10 import java.util.ArrayList; 11 import java.util.Arrays; 12 import java.util.Collection; 13 import java.util.Comparator; 14 import java.util.HashSet; 15 import java.util.Iterator; 16 import java.util.List; 17 import java.util.Locale; 18 import java.util.Map; 19 import java.util.Map.Entry; 20 import java.util.MissingResourceException; 21 import java.util.Random; 22 import java.util.Set; 23 import java.util.SortedMap; 24 25 import com.ibm.icu.dev.test.TestFmwk; 26 import com.ibm.icu.dev.test.TestLog; 27 import com.ibm.icu.impl.ICULocaleService; 28 import com.ibm.icu.impl.ICUService; 29 import com.ibm.icu.impl.ICUService.Factory; 30 import com.ibm.icu.impl.ICUService.SimpleFactory; 31 import com.ibm.icu.util.ULocale; 32 33 public class ICUServiceThreadTest extends TestFmwk 34 { 35 private static final boolean PRINTSTATS = false; 36 37 public static void main(String[] args) throws Exception { 38 ICUServiceThreadTest test = new ICUServiceThreadTest(); 39 test.run(args); 40 41 // get 42 // getvisibleids 43 // getdisplayname(locale) 44 // factories 45 46 // registerFactory 47 // unregisterFactory 48 49 // 1) concurrent access 50 // 2) access while factories change 51 // 3) iteration while factories change 52 // 4) concurrent conflicting access 53 } 54 55 private static final String[] countries = { 56 "ab", "bc", "cd", "de", "ef", "fg", "gh", "ji", "ij", "jk" 57 }; 58 private static final String[] languages = { 59 "", "ZY", "YX", "XW", "WV", "VU", "UT", "TS", "SR", "RQ", "QP" 60 }; 61 private static final String[] variants = { 62 "", "", "", "GOLD", "SILVER", "BRONZE" 63 }; 64 65 private static class TestFactory extends SimpleFactory { 66 TestFactory(String id) { 67 super(new ULocale(id), id, true); 68 } 69 70 public String getDisplayName(String idForDisplay, ULocale locale) { 71 return (visible && idForDisplay.equals(this.id)) ? "(" + locale.toString() + ") " + idForDisplay : null; 72 } 73 74 public String toString() { 75 return "Factory_" + id; 76 } 77 } 78 /** 79 * Convenience override of getDisplayNames(ULocale, Comparator, String) that 80 * uses the default collator for the locale as the comparator to 81 * sort the display names, and null for the matchID. 82 */ 83 public static SortedMap getDisplayNames(ICUService service, ULocale locale) { 84 Collator col; 85 try { 86 col = Collator.getInstance(locale.toLocale()); 87 } 88 catch (MissingResourceException e) { 89 // if no collator resources, we can't collate 90 col = null; 91 } 92 return service.getDisplayNames(locale, col, null); 93 } 94 private static final Random r = new Random(); // this is a multi thread test, can't 'unrandomize' 95 96 private static String getCLV() { 97 String c = countries[r.nextInt(countries.length)]; 98 String l = languages[r.nextInt(languages.length)]; 99 String v = variants[r.nextInt(variants.length)]; 100 return new Locale(c, l, v).toString(); 101 } 102 103 private static boolean WAIT = true; 104 private static boolean GO = false; 105 private static long TIME = 5000; 106 107 public static void runThreads() { 108 runThreads(TIME); 109 } 110 111 public static void runThreads(long time) { 112 try { 113 GO = true; 114 WAIT = false; 115 116 Thread.sleep(time); 117 118 WAIT = true; 119 GO = false; 120 121 Thread.sleep(300); 122 } 123 catch (InterruptedException e) { 124 } 125 } 126 127 static class TestThread extends Thread { 128 //private final String name; 129 protected ICUService service; 130 private final long delay; 131 protected final TestLog log; 132 133 public TestThread(String name, ICUService service, long delay, TestLog log) { 134 //this.name = name + " "; 135 this.service = service; 136 this.delay = delay; 137 this.log = new DelegatingLog(log); 138 this.setDaemon(true); 139 } 140 141 public void run() { 142 while (WAIT) { 143 Thread.yield(); 144 } 145 146 try { 147 while (GO) { 148 iterate(); 149 if (delay > 0) { 150 Thread.sleep(delay); 151 } 152 } 153 } 154 catch (InterruptedException e) { 155 } 156 } 157 158 protected void iterate() { 159 } 160 161 /* 162 public boolean logging() { 163 return log != null; 164 } 165 166 public void log(String msg) { 167 if (logging()) { 168 log.log(name + msg); 169 } 170 } 171 172 public void logln(String msg) { 173 if (logging()) { 174 log.logln(name + msg); 175 } 176 } 177 178 public void err(String msg) { 179 if (logging()) { 180 log.err(name + msg); 181 } 182 } 183 184 public void errln(String msg) { 185 if (logging()) { 186 log.errln(name + msg); 187 } 188 } 189 190 public void warn(String msg) { 191 if (logging()) { 192 log.info(name + msg); 193 } 194 } 195 196 public void warnln(String msg) { 197 if (logging()) { 198 log.infoln(name + msg); 199 } 200 } 201 */ 202 } 203 204 static class RegisterFactoryThread extends TestThread { 205 RegisterFactoryThread(String name, ICUService service, long delay, TestLog log) { 206 super("REG " + name, service, delay, log); 207 } 208 209 protected void iterate() { 210 Factory f = new TestFactory(getCLV()); 211 service.registerFactory(f); 212 log.logln(f.toString()); 213 } 214 } 215 216 static class UnregisterFactoryThread extends TestThread { 217 private Random r; 218 List factories; 219 220 UnregisterFactoryThread(String name, ICUService service, long delay, TestLog log) { 221 super("UNREG " + name, service, delay, log); 222 223 r = new Random(); 224 factories = service.factories(); 225 } 226 227 public void iterate() { 228 int s = factories.size(); 229 if (s == 0) { 230 factories = service.factories(); 231 } else { 232 int n = r.nextInt(s); 233 Factory f = (Factory)factories.remove(n); 234 boolean success = service.unregisterFactory(f); 235 log.logln("factory: " + f + (success ? " succeeded." : " *** failed.")); 236 } 237 } 238 } 239 240 static class UnregisterFactoryListThread extends TestThread { 241 Factory[] factories; 242 int n; 243 244 UnregisterFactoryListThread(String name, ICUService service, long delay, Factory[] factories, TestLog log) { 245 super("UNREG " + name, service, delay, log); 246 247 this.factories = factories; 248 } 249 250 public void iterate() { 251 if (n < factories.length) { 252 Factory f = factories[n++]; 253 boolean success = service.unregisterFactory(f); 254 log.logln("factory: " + f + (success ? " succeeded." : " *** failed.")); 255 } 256 } 257 } 258 259 260 static class GetVisibleThread extends TestThread { 261 GetVisibleThread(String name, ICUService service, long delay, TestLog log) { 262 super("VIS " + name, service, delay, log); 263 } 264 265 protected void iterate() { 266 Set ids = service.getVisibleIDs(); 267 Iterator iter = ids.iterator(); 268 int n = 10; 269 while (--n >= 0 && iter.hasNext()) { 270 String id = (String)iter.next(); 271 Object result = service.get(id); 272 log.logln("iter: " + n + " id: " + id + " result: " + result); 273 } 274 } 275 } 276 277 static class GetDisplayThread extends TestThread { 278 ULocale locale; 279 280 GetDisplayThread(String name, ICUService service, long delay, ULocale locale, TestLog log) { 281 super("DIS " + name, service, delay, log); 282 283 this.locale = locale; 284 } 285 286 protected void iterate() { 287 Map names = getDisplayNames(service,locale); 288 Iterator iter = names.entrySet().iterator(); 289 int n = 10; 290 while (--n >= 0 && iter.hasNext()) { 291 Entry e = (Entry)iter.next(); 292 String dname = (String)e.getKey(); 293 String id = (String)e.getValue(); 294 Object result = service.get(id); 295 296 // Note: IllegalMonitorStateException is thrown by the code 297 // below on IBM JRE5 for AIX 64bit. For some reason, converting 298 // int to String out of this statement resolves the issue. 299 300 //log.logln(" iter: " + n + 301 String num = Integer.toString(n); 302 log.logln(" iter: " + num + 303 " dname: " + dname + 304 " id: " + id + 305 " result: " + result); 306 } 307 } 308 } 309 310 static class GetThread extends TestThread { 311 private String[] actualID; 312 313 GetThread(String name, ICUService service, long delay, TestLog log) { 314 super("GET " + name, service, delay, log); 315 316 actualID = new String[1]; 317 } 318 319 protected void iterate() { 320 String id = getCLV(); 321 Object o = service.get(id, actualID); 322 if (o != null) { 323 log.logln(" id: " + id + " actual: " + actualID[0] + " result: " + o); 324 } 325 } 326 } 327 328 static class GetListThread extends TestThread { 329 private final String[] list; 330 private int n; 331 332 GetListThread(String name, ICUService service, long delay, String[] list, TestLog log) { 333 super("GETL " + name, service, delay, log); 334 335 this.list = list; 336 } 337 338 protected void iterate() { 339 if (--n < 0) { 340 n = list.length - 1; 341 } 342 String id = list[n]; 343 Object o = service.get(id); 344 log.logln(" id: " + id + " result: " + o); 345 } 346 } 347 348 // return a collection of unique factories, might be fewer than requested 349 Collection getFactoryCollection(int requested) { 350 Set locales = new HashSet(); 351 for (int i = 0; i < requested; ++i) { 352 locales.add(getCLV()); 353 } 354 List factories = new ArrayList(locales.size()); 355 Iterator iter = locales.iterator(); 356 while (iter.hasNext()) { 357 factories.add(new TestFactory((String)iter.next())); 358 } 359 return factories; 360 } 361 362 void registerFactories(ICUService service, Collection c) { 363 Iterator iter = c.iterator(); 364 while (iter.hasNext()) { 365 service.registerFactory((Factory)iter.next()); 366 } 367 } 368 369 ICUService stableService() { 370 if (stableService == null) { 371 stableService = new ICULocaleService(); 372 registerFactories(stableService, getFactoryCollection(50)); 373 } 374 if (PRINTSTATS) stableService.stats(); // Enable the stats collection 375 return stableService; 376 } 377 private ICUService stableService; 378 379 // run multiple get on a stable service 380 public void Test00_ConcurrentGet() { 381 for(int i = 0; i < 10; ++i) { 382 new GetThread("[" + Integer.toString(i) + "]", stableService(), 0, this).start(); 383 } 384 runThreads(); 385 if (PRINTSTATS) System.out.println(stableService.stats()); 386 } 387 388 // run multiple getVisibleID on a stable service 389 public void Test01_ConcurrentGetVisible() { 390 for(int i = 0; i < 10; ++i) { 391 new GetVisibleThread("[" + Integer.toString(i) + "]", stableService(), 0, this).start(); 392 } 393 runThreads(); 394 if (PRINTSTATS) System.out.println(stableService.stats()); 395 } 396 397 // run multiple getDisplayName on a stable service 398 public void Test02_ConcurrentGetDisplay() { 399 String[] localeNames = { 400 "en", "es", "de", "fr", "zh", "it", "no", "sv" 401 }; 402 for(int i = 0; i < localeNames.length; ++i) { 403 String locale = localeNames[i]; 404 new GetDisplayThread("[" + locale + "]", 405 stableService(), 406 0, 407 new ULocale(locale), 408 this).start(); 409 } 410 runThreads(); 411 if (PRINTSTATS) System.out.println(stableService.stats()); 412 } 413 414 // run register/unregister on a service 415 public void Test03_ConcurrentRegUnreg() { 416 ICUService service = new ICULocaleService(); 417 if (PRINTSTATS) service.stats(); // Enable the stats collection 418 for (int i = 0; i < 5; ++i) { 419 new RegisterFactoryThread("[" + i + "]", service, 0, this).start(); 420 } 421 for (int i = 0; i < 5; ++i) { 422 new UnregisterFactoryThread("[" + i + "]", service, 0, this).start(); 423 } 424 runThreads(); 425 if (PRINTSTATS) System.out.println(service.stats()); 426 } 427 428 public void Test04_WitheringService() { 429 ICUService service = new ICULocaleService(); 430 if (PRINTSTATS) service.stats(); // Enable the stats collection 431 432 Collection fc = getFactoryCollection(50); 433 registerFactories(service, fc); 434 435 Factory[] factories = (Factory[])fc.toArray(new Factory[fc.size()]); 436 Comparator comp = new Comparator() { 437 public int compare(Object lhs, Object rhs) { 438 return lhs.toString().compareTo(rhs.toString()); 439 } 440 }; 441 Arrays.sort(factories, comp); 442 443 new GetThread("", service, 0, this).start(); 444 new UnregisterFactoryListThread("", service, 3, factories, this).start(); 445 446 runThreads(2000); 447 if (PRINTSTATS) System.out.println(service.stats()); 448 } 449 450 // "all hell breaks loose" 451 // one register and one unregister thread, delay 500ms 452 // two display threads with different locales, delay 500ms; 453 // one visible id thread, delay 50ms 454 // fifteen get threads, delay 0 455 // run for ten seconds 456 public void Test05_ConcurrentEverything() { 457 ICUService service = new ICULocaleService(); 458 if (PRINTSTATS) service.stats(); // Enable the stats collection 459 460 new RegisterFactoryThread("", service, 500, this).start(); 461 462 for(int i = 0; i < 15; ++i) { 463 new GetThread("[" + Integer.toString(i) + "]", service, 0, this).start(); 464 } 465 466 new GetVisibleThread("", service, 50, this).start(); 467 468 String[] localeNames = { 469 "en", "de" 470 }; 471 for(int i = 0; i < localeNames.length; ++i) { 472 String locale = localeNames[i]; 473 new GetDisplayThread("[" + locale + "]", 474 stableService(), 475 500, 476 new ULocale(locale), 477 this).start(); 478 } 479 480 new UnregisterFactoryThread("", service, 500, this).start(); 481 482 // yoweee!!! 483 runThreads(9500); 484 if (PRINTSTATS) System.out.println(service.stats()); 485 } 486 } 487