2 *******************************************************************************
\r
3 * Copyright (C) 2001-2010, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.dev.test.util;
\r
9 import java.text.Collator;
\r
10 import java.util.ArrayList;
\r
11 import java.util.Arrays;
\r
12 import java.util.Collection;
\r
13 import java.util.Comparator;
\r
14 import java.util.HashSet;
\r
15 import java.util.Iterator;
\r
16 import java.util.List;
\r
17 import java.util.Locale;
\r
18 import java.util.Map;
\r
19 import java.util.MissingResourceException;
\r
20 import java.util.Random;
\r
21 import java.util.Set;
\r
22 import java.util.SortedMap;
\r
23 import java.util.Map.Entry;
\r
25 import com.ibm.icu.dev.test.TestFmwk;
\r
26 import com.ibm.icu.dev.test.TestLog;
\r
27 import com.ibm.icu.impl.ICULocaleService;
\r
28 import com.ibm.icu.impl.ICUService;
\r
29 import com.ibm.icu.impl.ICUService.Factory;
\r
30 import com.ibm.icu.impl.ICUService.SimpleFactory;
\r
31 import com.ibm.icu.util.ULocale;
\r
33 public class ICUServiceThreadTest extends TestFmwk
\r
35 private static final boolean PRINTSTATS = false;
\r
37 public static void main(String[] args) throws Exception {
\r
38 ICUServiceThreadTest test = new ICUServiceThreadTest();
\r
43 // getdisplayname(locale)
\r
47 // unregisterFactory
\r
49 // 1) concurrent access
\r
50 // 2) access while factories change
\r
51 // 3) iteration while factories change
\r
52 // 4) concurrent conflicting access
\r
55 private static final String[] countries = {
\r
56 "ab", "bc", "cd", "de", "ef", "fg", "gh", "ji", "ij", "jk"
\r
58 private static final String[] languages = {
\r
59 "", "ZY", "YX", "XW", "WV", "VU", "UT", "TS", "SR", "RQ", "QP"
\r
61 private static final String[] variants = {
\r
62 "", "", "", "GOLD", "SILVER", "BRONZE"
\r
65 private static class TestFactory extends SimpleFactory {
\r
66 TestFactory(String id) {
\r
67 super(new ULocale(id), id, true);
\r
70 public String getDisplayName(String idForDisplay, ULocale locale) {
\r
71 return (visible && idForDisplay.equals(this.id)) ? "(" + locale.toString() + ") " + idForDisplay : null;
\r
74 public String toString() {
\r
75 return "Factory_" + id;
\r
79 * Convenience override of getDisplayNames(ULocale, Comparator, String) that
\r
80 * uses the default collator for the locale as the comparator to
\r
81 * sort the display names, and null for the matchID.
\r
83 public static SortedMap getDisplayNames(ICUService service, ULocale locale) {
\r
86 col = Collator.getInstance(locale.toLocale());
\r
88 catch (MissingResourceException e) {
\r
89 // if no collator resources, we can't collate
\r
92 return service.getDisplayNames(locale, col, null);
\r
94 private static final Random r = new Random(); // this is a multi thread test, can't 'unrandomize'
\r
96 private static String getCLV() {
\r
97 String c = countries[r.nextInt(countries.length)];
\r
98 String l = languages[r.nextInt(languages.length)];
\r
99 String v = variants[r.nextInt(variants.length)];
\r
100 return new Locale(c, l, v).toString();
\r
103 private static boolean WAIT = true;
\r
104 private static boolean GO = false;
\r
105 private static long TIME = 5000;
\r
107 public static void runThreads() {
\r
111 public static void runThreads(long time) {
\r
116 Thread.sleep(time);
\r
123 catch (InterruptedException e) {
\r
127 static class TestThread extends Thread {
\r
128 //private final String name;
\r
129 protected ICUService service;
\r
130 private final long delay;
\r
131 protected final TestLog log;
\r
133 public TestThread(String name, ICUService service, long delay, TestLog log) {
\r
134 //this.name = name + " ";
\r
135 this.service = service;
\r
136 this.delay = delay;
\r
137 this.log = new DelegatingLog(log);
\r
138 this.setDaemon(true);
\r
141 public void run() {
\r
150 Thread.sleep(delay);
\r
154 catch (InterruptedException e) {
\r
158 protected void iterate() {
\r
162 public boolean logging() {
\r
163 return log != null;
\r
166 public void log(String msg) {
\r
168 log.log(name + msg);
\r
172 public void logln(String msg) {
\r
174 log.logln(name + msg);
\r
178 public void err(String msg) {
\r
180 log.err(name + msg);
\r
184 public void errln(String msg) {
\r
186 log.errln(name + msg);
\r
190 public void warn(String msg) {
\r
192 log.info(name + msg);
\r
196 public void warnln(String msg) {
\r
198 log.infoln(name + msg);
\r
204 static class RegisterFactoryThread extends TestThread {
\r
205 RegisterFactoryThread(String name, ICUService service, long delay, TestLog log) {
\r
206 super("REG " + name, service, delay, log);
\r
209 protected void iterate() {
\r
210 Factory f = new TestFactory(getCLV());
\r
211 service.registerFactory(f);
\r
212 log.logln(f.toString());
\r
216 static class UnregisterFactoryThread extends TestThread {
\r
220 UnregisterFactoryThread(String name, ICUService service, long delay, TestLog log) {
\r
221 super("UNREG " + name, service, delay, log);
\r
224 factories = service.factories();
\r
227 public void iterate() {
\r
228 int s = factories.size();
\r
230 factories = service.factories();
\r
232 int n = r.nextInt(s);
\r
233 Factory f = (Factory)factories.remove(n);
\r
234 boolean success = service.unregisterFactory(f);
\r
235 log.logln("factory: " + f + (success ? " succeeded." : " *** failed."));
\r
240 static class UnregisterFactoryListThread extends TestThread {
\r
241 Factory[] factories;
\r
244 UnregisterFactoryListThread(String name, ICUService service, long delay, Factory[] factories, TestLog log) {
\r
245 super("UNREG " + name, service, delay, log);
\r
247 this.factories = factories;
\r
250 public void iterate() {
\r
251 if (n < factories.length) {
\r
252 Factory f = factories[n++];
\r
253 boolean success = service.unregisterFactory(f);
\r
254 log.logln("factory: " + f + (success ? " succeeded." : " *** failed."));
\r
260 static class GetVisibleThread extends TestThread {
\r
261 GetVisibleThread(String name, ICUService service, long delay, TestLog log) {
\r
262 super("VIS " + name, service, delay, log);
\r
265 protected void iterate() {
\r
266 Set ids = service.getVisibleIDs();
\r
267 Iterator iter = ids.iterator();
\r
269 while (--n >= 0 && iter.hasNext()) {
\r
270 String id = (String)iter.next();
\r
271 Object result = service.get(id);
\r
272 log.logln("iter: " + n + " id: " + id + " result: " + result);
\r
277 static class GetDisplayThread extends TestThread {
\r
280 GetDisplayThread(String name, ICUService service, long delay, ULocale locale, TestLog log) {
\r
281 super("DIS " + name, service, delay, log);
\r
283 this.locale = locale;
\r
286 protected void iterate() {
\r
287 Map names = getDisplayNames(service,locale);
\r
288 Iterator iter = names.entrySet().iterator();
\r
290 while (--n >= 0 && iter.hasNext()) {
\r
291 Entry e = (Entry)iter.next();
\r
292 String dname = (String)e.getKey();
\r
293 String id = (String)e.getValue();
\r
294 Object result = service.get(id);
\r
296 // Note: IllegalMonitorStateException is thrown by the code
\r
297 // below on IBM JRE5 for AIX 64bit. For some reason, converting
\r
298 // int to String out of this statement resolves the issue.
\r
300 //log.logln(" iter: " + n +
\r
301 String num = Integer.toString(n);
\r
302 log.logln(" iter: " + num +
\r
303 " dname: " + dname +
\r
305 " result: " + result);
\r
310 static class GetThread extends TestThread {
\r
311 private String[] actualID;
\r
313 GetThread(String name, ICUService service, long delay, TestLog log) {
\r
314 super("GET " + name, service, delay, log);
\r
316 actualID = new String[1];
\r
319 protected void iterate() {
\r
320 String id = getCLV();
\r
321 Object o = service.get(id, actualID);
\r
323 log.logln(" id: " + id + " actual: " + actualID[0] + " result: " + o);
\r
328 static class GetListThread extends TestThread {
\r
329 private final String[] list;
\r
332 GetListThread(String name, ICUService service, long delay, String[] list, TestLog log) {
\r
333 super("GETL " + name, service, delay, log);
\r
338 protected void iterate() {
\r
340 n = list.length - 1;
\r
342 String id = list[n];
\r
343 Object o = service.get(id);
\r
344 log.logln(" id: " + id + " result: " + o);
\r
348 // return a collection of unique factories, might be fewer than requested
\r
349 Collection getFactoryCollection(int requested) {
\r
350 Set locales = new HashSet();
\r
351 for (int i = 0; i < requested; ++i) {
\r
352 locales.add(getCLV());
\r
354 List factories = new ArrayList(locales.size());
\r
355 Iterator iter = locales.iterator();
\r
356 while (iter.hasNext()) {
\r
357 factories.add(new TestFactory((String)iter.next()));
\r
362 void registerFactories(ICUService service, Collection c) {
\r
363 Iterator iter = c.iterator();
\r
364 while (iter.hasNext()) {
\r
365 service.registerFactory((Factory)iter.next());
\r
369 ICUService stableService() {
\r
370 if (stableService == null) {
\r
371 stableService = new ICULocaleService();
\r
372 registerFactories(stableService, getFactoryCollection(50));
\r
374 return stableService;
\r
376 private ICUService stableService;
\r
378 // run multiple get on a stable service
\r
379 public void Test00_ConcurrentGet() {
\r
380 for(int i = 0; i < 10; ++i) {
\r
381 new GetThread("[" + Integer.toString(i) + "]", stableService(), 0, this).start();
\r
384 if (PRINTSTATS) System.out.println(stableService.stats());
\r
387 // run multiple getVisibleID on a stable service
\r
388 public void Test01_ConcurrentGetVisible() {
\r
389 for(int i = 0; i < 10; ++i) {
\r
390 new GetVisibleThread("[" + Integer.toString(i) + "]", stableService(), 0, this).start();
\r
393 if (PRINTSTATS) System.out.println(stableService.stats());
\r
396 // run multiple getDisplayName on a stable service
\r
397 public void Test02_ConcurrentGetDisplay() {
\r
398 String[] localeNames = {
\r
399 "en", "es", "de", "fr", "zh", "it", "no", "sv"
\r
401 for(int i = 0; i < localeNames.length; ++i) {
\r
402 String locale = localeNames[i];
\r
403 new GetDisplayThread("[" + locale + "]",
\r
406 new ULocale(locale),
\r
410 if (PRINTSTATS) System.out.println(stableService.stats());
\r
413 // run register/unregister on a service
\r
414 public void Test03_ConcurrentRegUnreg() {
\r
415 ICUService service = new ICULocaleService();
\r
416 for (int i = 0; i < 5; ++i) {
\r
417 new RegisterFactoryThread("[" + i + "]", service, 0, this).start();
\r
419 for (int i = 0; i < 5; ++i) {
\r
420 new UnregisterFactoryThread("[" + i + "]", service, 0, this).start();
\r
423 if (PRINTSTATS) System.out.println(service.stats());
\r
426 public void Test04_WitheringService() {
\r
427 ICUService service = new ICULocaleService();
\r
429 Collection fc = getFactoryCollection(50);
\r
430 registerFactories(service, fc);
\r
432 Factory[] factories = (Factory[])fc.toArray(new Factory[fc.size()]);
\r
433 Comparator comp = new Comparator() {
\r
434 public int compare(Object lhs, Object rhs) {
\r
435 return lhs.toString().compareTo(rhs.toString());
\r
438 Arrays.sort(factories, comp);
\r
440 new GetThread("", service, 0, this).start();
\r
441 new UnregisterFactoryListThread("", service, 3, factories, this).start();
\r
444 if (PRINTSTATS) System.out.println(service.stats());
\r
447 // "all hell breaks loose"
\r
448 // one register and one unregister thread, delay 500ms
\r
449 // two display threads with different locales, delay 500ms;
\r
450 // one visible id thread, delay 50ms
\r
451 // fifteen get threads, delay 0
\r
452 // run for ten seconds
\r
453 public void Test05_ConcurrentEverything() {
\r
454 ICUService service = new ICULocaleService();
\r
456 new RegisterFactoryThread("", service, 500, this).start();
\r
458 for(int i = 0; i < 15; ++i) {
\r
459 new GetThread("[" + Integer.toString(i) + "]", service, 0, this).start();
\r
462 new GetVisibleThread("", service, 50, this).start();
\r
464 String[] localeNames = {
\r
467 for(int i = 0; i < localeNames.length; ++i) {
\r
468 String locale = localeNames[i];
\r
469 new GetDisplayThread("[" + locale + "]",
\r
472 new ULocale(locale),
\r
476 new UnregisterFactoryThread("", service, 500, this).start();
\r
480 if (PRINTSTATS) System.out.println(service.stats());
\r