2 *******************************************************************************
3 * Copyright (C) 2001-2010, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
7 package com.ibm.icu.dev.test.util;
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;
19 import java.util.Map.Entry;
20 import java.util.MissingResourceException;
21 import java.util.Random;
23 import java.util.SortedMap;
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;
33 public class ICUServiceThreadTest extends TestFmwk
35 private static final boolean PRINTSTATS = false;
37 public static void main(String[] args) throws Exception {
38 ICUServiceThreadTest test = new ICUServiceThreadTest();
43 // getdisplayname(locale)
49 // 1) concurrent access
50 // 2) access while factories change
51 // 3) iteration while factories change
52 // 4) concurrent conflicting access
55 private static final String[] countries = {
56 "ab", "bc", "cd", "de", "ef", "fg", "gh", "ji", "ij", "jk"
58 private static final String[] languages = {
59 "", "ZY", "YX", "XW", "WV", "VU", "UT", "TS", "SR", "RQ", "QP"
61 private static final String[] variants = {
62 "", "", "", "GOLD", "SILVER", "BRONZE"
65 private static class TestFactory extends SimpleFactory {
66 TestFactory(String id) {
67 super(new ULocale(id), id, true);
70 public String getDisplayName(String idForDisplay, ULocale locale) {
71 return (visible && idForDisplay.equals(this.id)) ? "(" + locale.toString() + ") " + idForDisplay : null;
74 public String toString() {
75 return "Factory_" + id;
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.
83 public static SortedMap getDisplayNames(ICUService service, ULocale locale) {
86 col = Collator.getInstance(locale.toLocale());
88 catch (MissingResourceException e) {
89 // if no collator resources, we can't collate
92 return service.getDisplayNames(locale, col, null);
94 private static final Random r = new Random(); // this is a multi thread test, can't 'unrandomize'
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();
103 private static boolean WAIT = true;
104 private static boolean GO = false;
105 private static long TIME = 5000;
107 public static void runThreads() {
111 public static void runThreads(long time) {
123 catch (InterruptedException e) {
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;
133 public TestThread(String name, ICUService service, long delay, TestLog log) {
134 //this.name = name + " ";
135 this.service = service;
137 this.log = new DelegatingLog(log);
138 this.setDaemon(true);
154 catch (InterruptedException e) {
158 protected void iterate() {
162 public boolean logging() {
166 public void log(String msg) {
172 public void logln(String msg) {
174 log.logln(name + msg);
178 public void err(String msg) {
184 public void errln(String msg) {
186 log.errln(name + msg);
190 public void warn(String msg) {
192 log.info(name + msg);
196 public void warnln(String msg) {
198 log.infoln(name + msg);
204 static class RegisterFactoryThread extends TestThread {
205 RegisterFactoryThread(String name, ICUService service, long delay, TestLog log) {
206 super("REG " + name, service, delay, log);
209 protected void iterate() {
210 Factory f = new TestFactory(getCLV());
211 service.registerFactory(f);
212 log.logln(f.toString());
216 static class UnregisterFactoryThread extends TestThread {
220 UnregisterFactoryThread(String name, ICUService service, long delay, TestLog log) {
221 super("UNREG " + name, service, delay, log);
224 factories = service.factories();
227 public void iterate() {
228 int s = factories.size();
230 factories = service.factories();
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."));
240 static class UnregisterFactoryListThread extends TestThread {
244 UnregisterFactoryListThread(String name, ICUService service, long delay, Factory[] factories, TestLog log) {
245 super("UNREG " + name, service, delay, log);
247 this.factories = factories;
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."));
260 static class GetVisibleThread extends TestThread {
261 GetVisibleThread(String name, ICUService service, long delay, TestLog log) {
262 super("VIS " + name, service, delay, log);
265 protected void iterate() {
266 Set ids = service.getVisibleIDs();
267 Iterator iter = ids.iterator();
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);
277 static class GetDisplayThread extends TestThread {
280 GetDisplayThread(String name, ICUService service, long delay, ULocale locale, TestLog log) {
281 super("DIS " + name, service, delay, log);
283 this.locale = locale;
286 protected void iterate() {
287 Map names = getDisplayNames(service,locale);
288 Iterator iter = names.entrySet().iterator();
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);
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.
300 //log.logln(" iter: " + n +
301 String num = Integer.toString(n);
302 log.logln(" iter: " + num +
305 " result: " + result);
310 static class GetThread extends TestThread {
311 private String[] actualID;
313 GetThread(String name, ICUService service, long delay, TestLog log) {
314 super("GET " + name, service, delay, log);
316 actualID = new String[1];
319 protected void iterate() {
320 String id = getCLV();
321 Object o = service.get(id, actualID);
323 log.logln(" id: " + id + " actual: " + actualID[0] + " result: " + o);
328 static class GetListThread extends TestThread {
329 private final String[] list;
332 GetListThread(String name, ICUService service, long delay, String[] list, TestLog log) {
333 super("GETL " + name, service, delay, log);
338 protected void iterate() {
343 Object o = service.get(id);
344 log.logln(" id: " + id + " result: " + o);
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());
354 List factories = new ArrayList(locales.size());
355 Iterator iter = locales.iterator();
356 while (iter.hasNext()) {
357 factories.add(new TestFactory((String)iter.next()));
362 void registerFactories(ICUService service, Collection c) {
363 Iterator iter = c.iterator();
364 while (iter.hasNext()) {
365 service.registerFactory((Factory)iter.next());
369 ICUService stableService() {
370 if (stableService == null) {
371 stableService = new ICULocaleService();
372 registerFactories(stableService, getFactoryCollection(50));
374 return stableService;
376 private ICUService stableService;
378 // run multiple get on a stable service
379 public void Test00_ConcurrentGet() {
380 for(int i = 0; i < 10; ++i) {
381 new GetThread("[" + Integer.toString(i) + "]", stableService(), 0, this).start();
384 if (PRINTSTATS) System.out.println(stableService.stats());
387 // run multiple getVisibleID on a stable service
388 public void Test01_ConcurrentGetVisible() {
389 for(int i = 0; i < 10; ++i) {
390 new GetVisibleThread("[" + Integer.toString(i) + "]", stableService(), 0, this).start();
393 if (PRINTSTATS) System.out.println(stableService.stats());
396 // run multiple getDisplayName on a stable service
397 public void Test02_ConcurrentGetDisplay() {
398 String[] localeNames = {
399 "en", "es", "de", "fr", "zh", "it", "no", "sv"
401 for(int i = 0; i < localeNames.length; ++i) {
402 String locale = localeNames[i];
403 new GetDisplayThread("[" + locale + "]",
410 if (PRINTSTATS) System.out.println(stableService.stats());
413 // run register/unregister on a service
414 public void Test03_ConcurrentRegUnreg() {
415 ICUService service = new ICULocaleService();
416 for (int i = 0; i < 5; ++i) {
417 new RegisterFactoryThread("[" + i + "]", service, 0, this).start();
419 for (int i = 0; i < 5; ++i) {
420 new UnregisterFactoryThread("[" + i + "]", service, 0, this).start();
423 if (PRINTSTATS) System.out.println(service.stats());
426 public void Test04_WitheringService() {
427 ICUService service = new ICULocaleService();
429 Collection fc = getFactoryCollection(50);
430 registerFactories(service, fc);
432 Factory[] factories = (Factory[])fc.toArray(new Factory[fc.size()]);
433 Comparator comp = new Comparator() {
434 public int compare(Object lhs, Object rhs) {
435 return lhs.toString().compareTo(rhs.toString());
438 Arrays.sort(factories, comp);
440 new GetThread("", service, 0, this).start();
441 new UnregisterFactoryListThread("", service, 3, factories, this).start();
444 if (PRINTSTATS) System.out.println(service.stats());
447 // "all hell breaks loose"
448 // one register and one unregister thread, delay 500ms
449 // two display threads with different locales, delay 500ms;
450 // one visible id thread, delay 50ms
451 // fifteen get threads, delay 0
452 // run for ten seconds
453 public void Test05_ConcurrentEverything() {
454 ICUService service = new ICULocaleService();
456 new RegisterFactoryThread("", service, 500, this).start();
458 for(int i = 0; i < 15; ++i) {
459 new GetThread("[" + Integer.toString(i) + "]", service, 0, this).start();
462 new GetVisibleThread("", service, 50, this).start();
464 String[] localeNames = {
467 for(int i = 0; i < localeNames.length; ++i) {
468 String locale = localeNames[i];
469 new GetDisplayThread("[" + locale + "]",
476 new UnregisterFactoryThread("", service, 500, this).start();
480 if (PRINTSTATS) System.out.println(service.stats());