Home | History | Annotate | Download | only in util
      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