001: /**
002: *******************************************************************************
003: * Copyright (C) 2001-2006, International Business Machines Corporation and *
004: * others. All Rights Reserved. *
005: *******************************************************************************
006: */package com.ibm.icu.dev.test.util;
007:
008: import com.ibm.icu.dev.test.TestFmwk;
009: import com.ibm.icu.dev.test.TestLog;
010: import com.ibm.icu.impl.ICUService;
011: import com.ibm.icu.impl.ICUService.Factory;
012: import com.ibm.icu.impl.ICUService.SimpleFactory;
013: import com.ibm.icu.impl.ICULocaleService;
014: import com.ibm.icu.text.Collator;
015: import com.ibm.icu.util.ULocale;
016:
017: import java.util.Arrays;
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.Comparator;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Locale;
025: import java.util.Map;
026: import java.util.Map.Entry;
027: import java.util.MissingResourceException;
028: import java.util.Random;
029: import java.util.Set;
030: import java.util.SortedMap;
031:
032: public class ICUServiceThreadTest extends TestFmwk {
033: private static final boolean PRINTSTATS = false;
034:
035: public static void main(String[] args) throws Exception {
036: ICUServiceThreadTest test = new ICUServiceThreadTest();
037: test.run(args);
038:
039: // get
040: // getvisibleids
041: // getdisplayname(locale)
042: // factories
043:
044: // registerFactory
045: // unregisterFactory
046:
047: // 1) concurrent access
048: // 2) access while factories change
049: // 3) iteration while factories change
050: // 4) concurrent conflicting access
051: }
052:
053: private static final String[] countries = { "ab", "bc", "cd", "de",
054: "ef", "fg", "gh", "ji", "ij", "jk" };
055: private static final String[] languages = { "", "ZY", "YX", "XW",
056: "WV", "VU", "UT", "TS", "SR", "RQ", "QP" };
057: private static final String[] variants = { "", "", "", "GOLD",
058: "SILVER", "BRONZE" };
059:
060: private static class TestFactory extends SimpleFactory {
061: TestFactory(String id) {
062: super (new ULocale(id), id, true);
063: }
064:
065: public String getDisplayName(String id, ULocale locale) {
066: return (visible && id.equals(this .id)) ? "("
067: + locale.toString() + ") " + id : null;
068: }
069:
070: public String toString() {
071: return "Factory_" + id;
072: }
073: }
074:
075: /**
076: * Convenience override of getDisplayNames(ULocale, Comparator, String) that
077: * uses the default collator for the locale as the comparator to
078: * sort the display names, and null for the matchID.
079: */
080: public static SortedMap getDisplayNames(ICUService service,
081: ULocale locale) {
082: Collator col;
083: try {
084: col = Collator.getInstance(locale);
085: } catch (MissingResourceException e) {
086: // if no collator resources, we can't collate
087: col = null;
088: }
089: return service.getDisplayNames(locale, col, null);
090: }
091:
092: private static final Random r = new Random(); // this is a multi thread test, can't 'unrandomize'
093:
094: private static String getCLV() {
095: String c = countries[r.nextInt(countries.length)];
096: String l = languages[r.nextInt(languages.length)];
097: String v = variants[r.nextInt(variants.length)];
098: return new Locale(c, l, v).toString();
099: }
100:
101: private static boolean WAIT = true;
102: private static boolean GO = false;
103: private static long TIME = 5000;
104:
105: public static void runThreads() {
106: runThreads(TIME);
107: }
108:
109: public static void runThreads(long time) {
110: try {
111: GO = true;
112: WAIT = false;
113:
114: Thread.sleep(time);
115:
116: WAIT = true;
117: GO = false;
118:
119: Thread.sleep(300);
120: } catch (InterruptedException e) {
121: }
122: }
123:
124: static class TestThread extends Thread {
125: private final String name;
126: protected ICUService service;
127: private final long delay;
128: protected final TestLog log;
129:
130: public TestThread(String name, ICUService service, long delay,
131: TestLog log) {
132: this .name = name + " ";
133: this .service = service;
134: this .delay = delay;
135: this .log = new DelegatingLog(log);
136: this .setDaemon(true);
137: }
138:
139: public void run() {
140: while (WAIT) {
141: Thread.yield();
142: }
143:
144: try {
145: while (GO) {
146: iterate();
147: if (delay > 0) {
148: Thread.sleep(delay);
149: }
150: }
151: } catch (InterruptedException e) {
152: }
153: }
154:
155: protected void iterate() {
156: }
157:
158: /*
159: public boolean logging() {
160: return log != null;
161: }
162:
163: public void log(String msg) {
164: if (logging()) {
165: log.log(name + msg);
166: }
167: }
168:
169: public void logln(String msg) {
170: if (logging()) {
171: log.logln(name + msg);
172: }
173: }
174:
175: public void err(String msg) {
176: if (logging()) {
177: log.err(name + msg);
178: }
179: }
180:
181: public void errln(String msg) {
182: if (logging()) {
183: log.errln(name + msg);
184: }
185: }
186:
187: public void warn(String msg) {
188: if (logging()) {
189: log.info(name + msg);
190: }
191: }
192:
193: public void warnln(String msg) {
194: if (logging()) {
195: log.infoln(name + msg);
196: }
197: }
198: */
199: }
200:
201: static class RegisterFactoryThread extends TestThread {
202: RegisterFactoryThread(String name, ICUService service,
203: long delay, TestLog log) {
204: super ("REG " + name, service, delay, log);
205: }
206:
207: protected void iterate() {
208: Factory f = new TestFactory(getCLV());
209: service.registerFactory(f);
210: log.logln(f.toString());
211: }
212: }
213:
214: static class UnregisterFactoryThread extends TestThread {
215: private Random r;
216: List factories;
217:
218: UnregisterFactoryThread(String name, ICUService service,
219: long delay, TestLog log) {
220: super ("UNREG " + name, service, delay, log);
221:
222: r = new Random();
223: factories = service.factories();
224: }
225:
226: public void iterate() {
227: int s = factories.size();
228: if (s == 0) {
229: factories = service.factories();
230: } else {
231: int n = r.nextInt(s);
232: Factory f = (Factory) factories.remove(n);
233: boolean success = service.unregisterFactory(f);
234: log.logln("factory: " + f
235: + (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,
245: long delay, Factory[] factories, TestLog log) {
246: super ("UNREG " + name, service, delay, log);
247:
248: this .factories = factories;
249: }
250:
251: public void iterate() {
252: if (n < factories.length) {
253: Factory f = factories[n++];
254: boolean success = service.unregisterFactory(f);
255: log.logln("factory: " + f
256: + (success ? " succeeded." : " *** failed."));
257: }
258: }
259: }
260:
261: static class GetVisibleThread extends TestThread {
262: GetVisibleThread(String name, ICUService service, long delay,
263: TestLog log) {
264: super ("VIS " + name, service, delay, log);
265: }
266:
267: protected void iterate() {
268: Set ids = service.getVisibleIDs();
269: Iterator iter = ids.iterator();
270: int n = 10;
271: while (--n >= 0 && iter.hasNext()) {
272: String id = (String) iter.next();
273: Object result = service.get(id);
274: log.logln("iter: " + n + " id: " + id + " result: "
275: + result);
276: }
277: }
278: }
279:
280: static class GetDisplayThread extends TestThread {
281: ULocale locale;
282:
283: GetDisplayThread(String name, ICUService service, long delay,
284: ULocale locale, TestLog log) {
285: super ("DIS " + name, service, delay, log);
286:
287: this .locale = locale;
288: }
289:
290: protected void iterate() {
291: Map names = getDisplayNames(service, locale);
292: Iterator iter = names.entrySet().iterator();
293: int n = 10;
294: while (--n >= 0 && iter.hasNext()) {
295: Entry e = (Entry) iter.next();
296: String dname = (String) e.getKey();
297: String id = (String) e.getValue();
298: Object result = service.get(id);
299:
300: // Note: IllegalMonitorStateException is thrown by the code
301: // below on IBM JRE5 for AIX 64bit. For some reason, converting
302: // int to String out of this statement resolves the issue.
303:
304: //log.logln(" iter: " + n +
305: String num = Integer.toString(n);
306: log.logln(" iter: " + num + " dname: " + dname
307: + " id: " + id + " result: " + result);
308: }
309: }
310: }
311:
312: static class GetThread extends TestThread {
313: private String[] actualID;
314:
315: GetThread(String name, ICUService service, long delay,
316: TestLog log) {
317: super ("GET " + name, service, delay, log);
318:
319: actualID = new String[1];
320: }
321:
322: protected void iterate() {
323: String id = getCLV();
324: Object o = service.get(id, actualID);
325: if (o != null) {
326: log.logln(" id: " + id + " actual: " + actualID[0]
327: + " result: " + o);
328: }
329: }
330: }
331:
332: static class GetListThread extends TestThread {
333: private final String[] list;
334: private int n;
335:
336: GetListThread(String name, ICUService service, long delay,
337: String[] list, TestLog log) {
338: super ("GETL " + name, service, delay, log);
339:
340: this .list = list;
341: }
342:
343: protected void iterate() {
344: if (--n < 0) {
345: n = list.length - 1;
346: }
347: String id = list[n];
348: Object o = service.get(id);
349: log.logln(" id: " + id + " result: " + o);
350: }
351: }
352:
353: // return a collection of unique factories, might be fewer than requested
354: Collection getFactoryCollection(int requested) {
355: Set locales = new HashSet();
356: for (int i = 0; i < requested; ++i) {
357: locales.add(getCLV());
358: }
359: List factories = new ArrayList(locales.size());
360: Iterator iter = locales.iterator();
361: while (iter.hasNext()) {
362: factories.add(new TestFactory((String) iter.next()));
363: }
364: return factories;
365: }
366:
367: void registerFactories(ICUService service, Collection c) {
368: Iterator iter = c.iterator();
369: while (iter.hasNext()) {
370: service.registerFactory((Factory) iter.next());
371: }
372: }
373:
374: ICUService stableService() {
375: if (stableService == null) {
376: stableService = new ICULocaleService();
377: registerFactories(stableService, getFactoryCollection(50));
378: }
379: return stableService;
380: }
381:
382: private ICUService stableService;
383:
384: // run multiple get on a stable service
385: public void Test00_ConcurrentGet() {
386: for (int i = 0; i < 10; ++i) {
387: new GetThread("[" + Integer.toString(i) + "]",
388: stableService(), 0, this ).start();
389: }
390: runThreads();
391: if (PRINTSTATS)
392: System.out.println(stableService.stats());
393: }
394:
395: // run multiple getVisibleID on a stable service
396: public void Test01_ConcurrentGetVisible() {
397: for (int i = 0; i < 10; ++i) {
398: new GetVisibleThread("[" + Integer.toString(i) + "]",
399: stableService(), 0, this ).start();
400: }
401: runThreads();
402: if (PRINTSTATS)
403: System.out.println(stableService.stats());
404: }
405:
406: // run multiple getDisplayName on a stable service
407: public void Test02_ConcurrentGetDisplay() {
408: String[] localeNames = { "en", "es", "de", "fr", "zh", "it",
409: "no", "sv" };
410: for (int i = 0; i < localeNames.length; ++i) {
411: String locale = localeNames[i];
412: new GetDisplayThread("[" + locale + "]", stableService(),
413: 0, new ULocale(locale), this ).start();
414: }
415: runThreads();
416: if (PRINTSTATS)
417: System.out.println(stableService.stats());
418: }
419:
420: // run register/unregister on a service
421: public void Test03_ConcurrentRegUnreg() {
422: ICUService service = new ICULocaleService();
423: for (int i = 0; i < 5; ++i) {
424: new RegisterFactoryThread("[" + i + "]", service, 0, this )
425: .start();
426: }
427: for (int i = 0; i < 5; ++i) {
428: new UnregisterFactoryThread("[" + i + "]", service, 0, this )
429: .start();
430: }
431: runThreads();
432: if (PRINTSTATS)
433: System.out.println(service.stats());
434: }
435:
436: public void Test04_WitheringService() {
437: ICUService service = new ICULocaleService();
438:
439: Collection fc = getFactoryCollection(50);
440: registerFactories(service, fc);
441:
442: Factory[] factories = (Factory[]) fc.toArray(new Factory[fc
443: .size()]);
444: Comparator comp = new Comparator() {
445: public int compare(Object lhs, Object rhs) {
446: return lhs.toString().compareTo(rhs.toString());
447: }
448: };
449: Arrays.sort(factories, comp);
450:
451: new GetThread("", service, 0, this ).start();
452: new UnregisterFactoryListThread("", service, 3, factories, this )
453: .start();
454:
455: runThreads(2000);
456: if (PRINTSTATS)
457: System.out.println(service.stats());
458: }
459:
460: // "all hell breaks loose"
461: // one register and one unregister thread, delay 500ms
462: // two display threads with different locales, delay 500ms;
463: // one visible id thread, delay 50ms
464: // fifteen get threads, delay 0
465: // run for ten seconds
466: public void Test05_ConcurrentEverything() {
467: ICUService service = new ICULocaleService();
468:
469: new RegisterFactoryThread("", service, 500, this ).start();
470:
471: for (int i = 0; i < 15; ++i) {
472: new GetThread("[" + Integer.toString(i) + "]", service, 0,
473: this ).start();
474: }
475:
476: new GetVisibleThread("", service, 50, this ).start();
477:
478: String[] localeNames = { "en", "de" };
479: for (int i = 0; i < localeNames.length; ++i) {
480: String locale = localeNames[i];
481: new GetDisplayThread("[" + locale + "]", stableService(),
482: 500, new ULocale(locale), this ).start();
483: }
484:
485: new UnregisterFactoryThread("", service, 500, this ).start();
486:
487: // yoweee!!!
488: runThreads(10000);
489: if (PRINTSTATS)
490: System.out.println(service.stats());
491: }
492: }
|