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