Home | History | Annotate | Download | only in common
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /**
      4 *******************************************************************************
      5 * Copyright (C) 2001-2014, International Business Machines Corporation.
      6 * All Rights Reserved.
      7 *******************************************************************************
      8 */
      9 
     10 #include "unicode/utypes.h"
     11 
     12 #if !UCONFIG_NO_SERVICE
     13 
     14 #include "serv.h"
     15 #include "umutex.h"
     16 
     17 #undef SERVICE_REFCOUNT
     18 
     19 // in case we use the refcount stuff
     20 
     21 U_NAMESPACE_BEGIN
     22 
     23 /*
     24 ******************************************************************
     25 */
     26 
     27 const UChar ICUServiceKey::PREFIX_DELIMITER = 0x002F;   /* '/' */
     28 
     29 ICUServiceKey::ICUServiceKey(const UnicodeString& id)
     30 : _id(id) {
     31 }
     32 
     33 ICUServiceKey::~ICUServiceKey()
     34 {
     35 }
     36 
     37 const UnicodeString&
     38 ICUServiceKey::getID() const
     39 {
     40     return _id;
     41 }
     42 
     43 UnicodeString&
     44 ICUServiceKey::canonicalID(UnicodeString& result) const
     45 {
     46     return result.append(_id);
     47 }
     48 
     49 UnicodeString&
     50 ICUServiceKey::currentID(UnicodeString& result) const
     51 {
     52     return canonicalID(result);
     53 }
     54 
     55 UnicodeString&
     56 ICUServiceKey::currentDescriptor(UnicodeString& result) const
     57 {
     58     prefix(result);
     59     result.append(PREFIX_DELIMITER);
     60     return currentID(result);
     61 }
     62 
     63 UBool
     64 ICUServiceKey::fallback()
     65 {
     66     return FALSE;
     67 }
     68 
     69 UBool
     70 ICUServiceKey::isFallbackOf(const UnicodeString& id) const
     71 {
     72     return id == _id;
     73 }
     74 
     75 UnicodeString&
     76 ICUServiceKey::prefix(UnicodeString& result) const
     77 {
     78     return result;
     79 }
     80 
     81 UnicodeString&
     82 ICUServiceKey::parsePrefix(UnicodeString& result)
     83 {
     84     int32_t n = result.indexOf(PREFIX_DELIMITER);
     85     if (n < 0) {
     86         n = 0;
     87     }
     88     result.remove(n);
     89     return result;
     90 }
     91 
     92 UnicodeString&
     93 ICUServiceKey::parseSuffix(UnicodeString& result)
     94 {
     95     int32_t n = result.indexOf(PREFIX_DELIMITER);
     96     if (n >= 0) {
     97         result.remove(0, n+1);
     98     }
     99     return result;
    100 }
    101 
    102 #ifdef SERVICE_DEBUG
    103 UnicodeString&
    104 ICUServiceKey::debug(UnicodeString& result) const
    105 {
    106     debugClass(result);
    107     result.append((UnicodeString)" id: ");
    108     result.append(_id);
    109     return result;
    110 }
    111 
    112 UnicodeString&
    113 ICUServiceKey::debugClass(UnicodeString& result) const
    114 {
    115     return result.append((UnicodeString)"ICUServiceKey");
    116 }
    117 #endif
    118 
    119 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUServiceKey)
    120 
    121 /*
    122 ******************************************************************
    123 */
    124 
    125 ICUServiceFactory::~ICUServiceFactory() {}
    126 
    127 SimpleFactory::SimpleFactory(UObject* instanceToAdopt, const UnicodeString& id, UBool visible)
    128 : _instance(instanceToAdopt), _id(id), _visible(visible)
    129 {
    130 }
    131 
    132 SimpleFactory::~SimpleFactory()
    133 {
    134     delete _instance;
    135 }
    136 
    137 UObject*
    138 SimpleFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const
    139 {
    140     if (U_SUCCESS(status)) {
    141         UnicodeString temp;
    142         if (_id == key.currentID(temp)) {
    143             return service->cloneInstance(_instance);
    144         }
    145     }
    146     return NULL;
    147 }
    148 
    149 void
    150 SimpleFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const
    151 {
    152     if (_visible) {
    153         result.put(_id, (void*)this, status); // cast away const
    154     } else {
    155         result.remove(_id);
    156     }
    157 }
    158 
    159 UnicodeString&
    160 SimpleFactory::getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const
    161 {
    162     if (_visible && _id == id) {
    163         result = _id;
    164     } else {
    165         result.setToBogus();
    166     }
    167     return result;
    168 }
    169 
    170 #ifdef SERVICE_DEBUG
    171 UnicodeString&
    172 SimpleFactory::debug(UnicodeString& toAppendTo) const
    173 {
    174     debugClass(toAppendTo);
    175     toAppendTo.append((UnicodeString)" id: ");
    176     toAppendTo.append(_id);
    177     toAppendTo.append((UnicodeString)", visible: ");
    178     toAppendTo.append(_visible ? (UnicodeString)"T" : (UnicodeString)"F");
    179     return toAppendTo;
    180 }
    181 
    182 UnicodeString&
    183 SimpleFactory::debugClass(UnicodeString& toAppendTo) const
    184 {
    185     return toAppendTo.append((UnicodeString)"SimpleFactory");
    186 }
    187 #endif
    188 
    189 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleFactory)
    190 
    191 /*
    192 ******************************************************************
    193 */
    194 
    195 ServiceListener::~ServiceListener() {}
    196 
    197 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceListener)
    198 
    199 /*
    200 ******************************************************************
    201 */
    202 
    203 // Record the actual id for this service in the cache, so we can return it
    204 // even if we succeed later with a different id.
    205 class CacheEntry : public UMemory {
    206 private:
    207     int32_t refcount;
    208 
    209 public:
    210     UnicodeString actualDescriptor;
    211     UObject* service;
    212 
    213     /**
    214     * Releases a reference to the shared resource.
    215     */
    216     ~CacheEntry() {
    217         delete service;
    218     }
    219 
    220     CacheEntry(const UnicodeString& _actualDescriptor, UObject* _service)
    221         : refcount(1), actualDescriptor(_actualDescriptor), service(_service) {
    222     }
    223 
    224     /**
    225     * Instantiation creates an initial reference, so don't call this
    226     * unless you're creating a new pointer to this.  Management of
    227     * that pointer will have to know how to deal with refcounts.
    228     * Return true if the resource has not already been released.
    229     */
    230     CacheEntry* ref() {
    231         ++refcount;
    232         return this;
    233     }
    234 
    235     /**
    236     * Destructions removes a reference, so don't call this unless
    237     * you're removing pointer to this somewhere.  Management of that
    238     * pointer will have to know how to deal with refcounts.  Once
    239     * the refcount drops to zero, the resource is released.  Return
    240     * false if the resouce has been released.
    241     */
    242     CacheEntry* unref() {
    243         if ((--refcount) == 0) {
    244             delete this;
    245             return NULL;
    246         }
    247         return this;
    248     }
    249 
    250     /**
    251     * Return TRUE if there is at least one reference to this and the
    252     * resource has not been released.
    253     */
    254     UBool isShared() const {
    255         return refcount > 1;
    256     }
    257 };
    258 
    259 // UObjectDeleter for serviceCache
    260 U_CDECL_BEGIN
    261 static void U_CALLCONV
    262 cacheDeleter(void* obj) {
    263     U_NAMESPACE_USE ((CacheEntry*)obj)->unref();
    264 }
    265 
    266 /**
    267 * Deleter for UObjects
    268 */
    269 static void U_CALLCONV
    270 deleteUObject(void *obj) {
    271     U_NAMESPACE_USE delete (UObject*) obj;
    272 }
    273 U_CDECL_END
    274 
    275 /*
    276 ******************************************************************
    277 */
    278 
    279 class DNCache : public UMemory {
    280 public:
    281     Hashtable cache;
    282     const Locale locale;
    283 
    284     DNCache(const Locale& _locale)
    285         : cache(), locale(_locale)
    286     {
    287         // cache.setKeyDeleter(uprv_deleteUObject);
    288     }
    289 };
    290 
    291 
    292 /*
    293 ******************************************************************
    294 */
    295 
    296 StringPair*
    297 StringPair::create(const UnicodeString& displayName,
    298                    const UnicodeString& id,
    299                    UErrorCode& status)
    300 {
    301     if (U_SUCCESS(status)) {
    302         StringPair* sp = new StringPair(displayName, id);
    303         if (sp == NULL || sp->isBogus()) {
    304             status = U_MEMORY_ALLOCATION_ERROR;
    305             delete sp;
    306             return NULL;
    307         }
    308         return sp;
    309     }
    310     return NULL;
    311 }
    312 
    313 UBool
    314 StringPair::isBogus() const {
    315     return displayName.isBogus() || id.isBogus();
    316 }
    317 
    318 StringPair::StringPair(const UnicodeString& _displayName,
    319                        const UnicodeString& _id)
    320 : displayName(_displayName)
    321 , id(_id)
    322 {
    323 }
    324 
    325 U_CDECL_BEGIN
    326 static void U_CALLCONV
    327 userv_deleteStringPair(void *obj) {
    328     U_NAMESPACE_USE delete (StringPair*) obj;
    329 }
    330 U_CDECL_END
    331 
    332 /*
    333 ******************************************************************
    334 */
    335 
    336 static UMutex lock = U_MUTEX_INITIALIZER;
    337 
    338 ICUService::ICUService()
    339 : name()
    340 , timestamp(0)
    341 , factories(NULL)
    342 , serviceCache(NULL)
    343 , idCache(NULL)
    344 , dnCache(NULL)
    345 {
    346 }
    347 
    348 ICUService::ICUService(const UnicodeString& newName)
    349 : name(newName)
    350 , timestamp(0)
    351 , factories(NULL)
    352 , serviceCache(NULL)
    353 , idCache(NULL)
    354 , dnCache(NULL)
    355 {
    356 }
    357 
    358 ICUService::~ICUService()
    359 {
    360     {
    361         Mutex mutex(&lock);
    362         clearCaches();
    363         delete factories;
    364         factories = NULL;
    365     }
    366 }
    367 
    368 UObject*
    369 ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const
    370 {
    371     return get(descriptor, NULL, status);
    372 }
    373 
    374 UObject*
    375 ICUService::get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const
    376 {
    377     UObject* result = NULL;
    378     ICUServiceKey* key = createKey(&descriptor, status);
    379     if (key) {
    380         result = getKey(*key, actualReturn, status);
    381         delete key;
    382     }
    383     return result;
    384 }
    385 
    386 UObject*
    387 ICUService::getKey(ICUServiceKey& key, UErrorCode& status) const
    388 {
    389     return getKey(key, NULL, status);
    390 }
    391 
    392 // this is a vector that subclasses of ICUService can override to further customize the result object
    393 // before returning it.  All other public get functions should call this one.
    394 
    395 UObject*
    396 ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const
    397 {
    398     return getKey(key, actualReturn, NULL, status);
    399 }
    400 
    401 // make it possible to call reentrantly on systems that don't have reentrant mutexes.
    402 // we can use this simple approach since we know the situation where we're calling
    403 // reentrantly even without knowing the thread.
    404 class XMutex : public UMemory {
    405 public:
    406     inline XMutex(UMutex *mutex, UBool reentering)
    407         : fMutex(mutex)
    408         , fActive(!reentering)
    409     {
    410         if (fActive) umtx_lock(fMutex);
    411     }
    412     inline ~XMutex() {
    413         if (fActive) umtx_unlock(fMutex);
    414     }
    415 
    416 private:
    417     UMutex  *fMutex;
    418     UBool fActive;
    419 };
    420 
    421 struct UVectorDeleter {
    422     UVector* _obj;
    423     UVectorDeleter() : _obj(NULL) {}
    424     ~UVectorDeleter() { delete _obj; }
    425 };
    426 
    427 // called only by factories, treat as private
    428 UObject*
    429 ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUServiceFactory* factory, UErrorCode& status) const
    430 {
    431     if (U_FAILURE(status)) {
    432         return NULL;
    433     }
    434 
    435     if (isDefault()) {
    436         return handleDefault(key, actualReturn, status);
    437     }
    438 
    439     ICUService* ncthis = (ICUService*)this; // cast away semantic const
    440 
    441     CacheEntry* result = NULL;
    442     {
    443         // The factory list can't be modified until we're done,
    444         // otherwise we might update the cache with an invalid result.
    445         // The cache has to stay in synch with the factory list.
    446         // ICU doesn't have monitors so we can't use rw locks, so
    447         // we single-thread everything using this service, for now.
    448 
    449         // if factory is not null, we're calling from within the mutex,
    450         // and since some unix machines don't have reentrant mutexes we
    451         // need to make sure not to try to lock it again.
    452         XMutex mutex(&lock, factory != NULL);
    453 
    454         if (serviceCache == NULL) {
    455             ncthis->serviceCache = new Hashtable(status);
    456             if (ncthis->serviceCache == NULL) {
    457                 return NULL;
    458             }
    459             if (U_FAILURE(status)) {
    460                 delete serviceCache;
    461                 return NULL;
    462             }
    463             serviceCache->setValueDeleter(cacheDeleter);
    464         }
    465 
    466         UnicodeString currentDescriptor;
    467         UVectorDeleter cacheDescriptorList;
    468         UBool putInCache = FALSE;
    469 
    470         int32_t startIndex = 0;
    471         int32_t limit = factories->size();
    472         UBool cacheResult = TRUE;
    473 
    474         if (factory != NULL) {
    475             for (int32_t i = 0; i < limit; ++i) {
    476                 if (factory == (const ICUServiceFactory*)factories->elementAt(i)) {
    477                     startIndex = i + 1;
    478                     break;
    479                 }
    480             }
    481             if (startIndex == 0) {
    482                 // throw new InternalError("Factory " + factory + "not registered with service: " + this);
    483                 status = U_ILLEGAL_ARGUMENT_ERROR;
    484                 return NULL;
    485             }
    486             cacheResult = FALSE;
    487         }
    488 
    489         do {
    490             currentDescriptor.remove();
    491             key.currentDescriptor(currentDescriptor);
    492             result = (CacheEntry*)serviceCache->get(currentDescriptor);
    493             if (result != NULL) {
    494                 break;
    495             }
    496 
    497             // first test of cache failed, so we'll have to update
    498             // the cache if we eventually succeed-- that is, if we're
    499             // going to update the cache at all.
    500             putInCache = TRUE;
    501 
    502             int32_t index = startIndex;
    503             while (index < limit) {
    504                 ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(index++);
    505                 UObject* service = f->create(key, this, status);
    506                 if (U_FAILURE(status)) {
    507                     delete service;
    508                     return NULL;
    509                 }
    510                 if (service != NULL) {
    511                     result = new CacheEntry(currentDescriptor, service);
    512                     if (result == NULL) {
    513                         delete service;
    514                         status = U_MEMORY_ALLOCATION_ERROR;
    515                         return NULL;
    516                     }
    517 
    518                     goto outerEnd;
    519                 }
    520             }
    521 
    522             // prepare to load the cache with all additional ids that
    523             // will resolve to result, assuming we'll succeed.  We
    524             // don't want to keep querying on an id that's going to
    525             // fallback to the one that succeeded, we want to hit the
    526             // cache the first time next goaround.
    527             if (cacheDescriptorList._obj == NULL) {
    528                 cacheDescriptorList._obj = new UVector(uprv_deleteUObject, NULL, 5, status);
    529                 if (U_FAILURE(status)) {
    530                     return NULL;
    531                 }
    532             }
    533             UnicodeString* idToCache = new UnicodeString(currentDescriptor);
    534             if (idToCache == NULL || idToCache->isBogus()) {
    535                 status = U_MEMORY_ALLOCATION_ERROR;
    536                 return NULL;
    537             }
    538 
    539             cacheDescriptorList._obj->addElement(idToCache, status);
    540             if (U_FAILURE(status)) {
    541                 return NULL;
    542             }
    543         } while (key.fallback());
    544 outerEnd:
    545 
    546         if (result != NULL) {
    547             if (putInCache && cacheResult) {
    548                 serviceCache->put(result->actualDescriptor, result, status);
    549                 if (U_FAILURE(status)) {
    550                     return NULL;
    551                 }
    552 
    553                 if (cacheDescriptorList._obj != NULL) {
    554                     for (int32_t i = cacheDescriptorList._obj->size(); --i >= 0;) {
    555                         UnicodeString* desc = (UnicodeString*)cacheDescriptorList._obj->elementAt(i);
    556 
    557                         serviceCache->put(*desc, result, status);
    558                         if (U_FAILURE(status)) {
    559                             return NULL;
    560                         }
    561 
    562                         result->ref();
    563                         cacheDescriptorList._obj->removeElementAt(i);
    564                     }
    565                 }
    566             }
    567 
    568             if (actualReturn != NULL) {
    569                 // strip null prefix
    570                 if (result->actualDescriptor.indexOf((UChar)0x2f) == 0) { // U+002f=slash (/)
    571                     actualReturn->remove();
    572                     actualReturn->append(result->actualDescriptor,
    573                         1,
    574                         result->actualDescriptor.length() - 1);
    575                 } else {
    576                     *actualReturn = result->actualDescriptor;
    577                 }
    578 
    579                 if (actualReturn->isBogus()) {
    580                     status = U_MEMORY_ALLOCATION_ERROR;
    581                     delete result;
    582                     return NULL;
    583                 }
    584             }
    585 
    586             UObject* service = cloneInstance(result->service);
    587             if (putInCache && !cacheResult) {
    588                 delete result;
    589             }
    590             return service;
    591         }
    592     }
    593 
    594     return handleDefault(key, actualReturn, status);
    595 }
    596 
    597 UObject*
    598 ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const
    599 {
    600     return NULL;
    601 }
    602 
    603 UVector&
    604 ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const {
    605     return getVisibleIDs(result, NULL, status);
    606 }
    607 
    608 UVector&
    609 ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const
    610 {
    611     result.removeAllElements();
    612 
    613     if (U_FAILURE(status)) {
    614         return result;
    615     }
    616 
    617     {
    618         Mutex mutex(&lock);
    619         const Hashtable* map = getVisibleIDMap(status);
    620         if (map != NULL) {
    621             ICUServiceKey* fallbackKey = createKey(matchID, status);
    622 
    623             for (int32_t pos = UHASH_FIRST;;) {
    624                 const UHashElement* e = map->nextElement(pos);
    625                 if (e == NULL) {
    626                     break;
    627                 }
    628 
    629                 const UnicodeString* id = (const UnicodeString*)e->key.pointer;
    630                 if (fallbackKey != NULL) {
    631                     if (!fallbackKey->isFallbackOf(*id)) {
    632                         continue;
    633                     }
    634                 }
    635 
    636                 UnicodeString* idClone = new UnicodeString(*id);
    637                 if (idClone == NULL || idClone->isBogus()) {
    638                     delete idClone;
    639                     status = U_MEMORY_ALLOCATION_ERROR;
    640                     break;
    641                 }
    642                 result.addElement(idClone, status);
    643                 if (U_FAILURE(status)) {
    644                     delete idClone;
    645                     break;
    646                 }
    647             }
    648             delete fallbackKey;
    649         }
    650     }
    651     if (U_FAILURE(status)) {
    652         result.removeAllElements();
    653     }
    654     return result;
    655 }
    656 
    657 const Hashtable*
    658 ICUService::getVisibleIDMap(UErrorCode& status) const {
    659     if (U_FAILURE(status)) return NULL;
    660 
    661     // must only be called when lock is already held
    662 
    663     ICUService* ncthis = (ICUService*)this; // cast away semantic const
    664     if (idCache == NULL) {
    665         ncthis->idCache = new Hashtable(status);
    666         if (idCache == NULL) {
    667             status = U_MEMORY_ALLOCATION_ERROR;
    668         } else if (factories != NULL) {
    669             for (int32_t pos = factories->size(); --pos >= 0;) {
    670                 ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(pos);
    671                 f->updateVisibleIDs(*idCache, status);
    672             }
    673             if (U_FAILURE(status)) {
    674                 delete idCache;
    675                 ncthis->idCache = NULL;
    676             }
    677         }
    678     }
    679 
    680     return idCache;
    681 }
    682 
    683 
    684 UnicodeString&
    685 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const
    686 {
    687     return getDisplayName(id, result, Locale::getDefault());
    688 }
    689 
    690 UnicodeString&
    691 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const
    692 {
    693     {
    694         UErrorCode status = U_ZERO_ERROR;
    695         Mutex mutex(&lock);
    696         const Hashtable* map = getVisibleIDMap(status);
    697         if (map != NULL) {
    698             ICUServiceFactory* f = (ICUServiceFactory*)map->get(id);
    699             if (f != NULL) {
    700                 f->getDisplayName(id, locale, result);
    701                 return result;
    702             }
    703 
    704             // fallback
    705             status = U_ZERO_ERROR;
    706             ICUServiceKey* fallbackKey = createKey(&id, status);
    707             while (fallbackKey != NULL && fallbackKey->fallback()) {
    708                 UnicodeString us;
    709                 fallbackKey->currentID(us);
    710                 f = (ICUServiceFactory*)map->get(us);
    711                 if (f != NULL) {
    712                     f->getDisplayName(id, locale, result);
    713                     delete fallbackKey;
    714                     return result;
    715                 }
    716             }
    717             delete fallbackKey;
    718         }
    719     }
    720     result.setToBogus();
    721     return result;
    722 }
    723 
    724 UVector&
    725 ICUService::getDisplayNames(UVector& result, UErrorCode& status) const
    726 {
    727     return getDisplayNames(result, Locale::getDefault(), NULL, status);
    728 }
    729 
    730 
    731 UVector&
    732 ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const
    733 {
    734     return getDisplayNames(result, locale, NULL, status);
    735 }
    736 
    737 UVector&
    738 ICUService::getDisplayNames(UVector& result,
    739                             const Locale& locale,
    740                             const UnicodeString* matchID,
    741                             UErrorCode& status) const
    742 {
    743     result.removeAllElements();
    744     result.setDeleter(userv_deleteStringPair);
    745     if (U_SUCCESS(status)) {
    746         ICUService* ncthis = (ICUService*)this; // cast away semantic const
    747         Mutex mutex(&lock);
    748 
    749         if (dnCache != NULL && dnCache->locale != locale) {
    750             delete dnCache;
    751             ncthis->dnCache = NULL;
    752         }
    753 
    754         if (dnCache == NULL) {
    755             const Hashtable* m = getVisibleIDMap(status);
    756             if (U_FAILURE(status)) {
    757                 return result;
    758             }
    759             ncthis->dnCache = new DNCache(locale);
    760             if (dnCache == NULL) {
    761                 status = U_MEMORY_ALLOCATION_ERROR;
    762                 return result;
    763             }
    764 
    765             int32_t pos = UHASH_FIRST;
    766             const UHashElement* entry = NULL;
    767             while ((entry = m->nextElement(pos)) != NULL) {
    768                 const UnicodeString* id = (const UnicodeString*)entry->key.pointer;
    769                 ICUServiceFactory* f = (ICUServiceFactory*)entry->value.pointer;
    770                 UnicodeString dname;
    771                 f->getDisplayName(*id, locale, dname);
    772                 if (dname.isBogus()) {
    773                     status = U_MEMORY_ALLOCATION_ERROR;
    774                 } else {
    775                     dnCache->cache.put(dname, (void*)id, status); // share pointer with visibleIDMap
    776                     if (U_SUCCESS(status)) {
    777                         continue;
    778                     }
    779                 }
    780                 delete dnCache;
    781                 ncthis->dnCache = NULL;
    782                 return result;
    783             }
    784         }
    785     }
    786 
    787     ICUServiceKey* matchKey = createKey(matchID, status);
    788     /* To ensure that all elements in the hashtable are iterated, set pos to -1.
    789      * nextElement(pos) will skip the position at pos and begin the iteration
    790      * at the next position, which in this case will be 0.
    791      */
    792     int32_t pos = UHASH_FIRST;
    793     const UHashElement *entry = NULL;
    794     while ((entry = dnCache->cache.nextElement(pos)) != NULL) {
    795         const UnicodeString* id = (const UnicodeString*)entry->value.pointer;
    796         if (matchKey != NULL && !matchKey->isFallbackOf(*id)) {
    797             continue;
    798         }
    799         const UnicodeString* dn = (const UnicodeString*)entry->key.pointer;
    800         StringPair* sp = StringPair::create(*id, *dn, status);
    801         result.addElement(sp, status);
    802         if (U_FAILURE(status)) {
    803             result.removeAllElements();
    804             break;
    805         }
    806     }
    807     delete matchKey;
    808 
    809     return result;
    810 }
    811 
    812 URegistryKey
    813 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status)
    814 {
    815     return registerInstance(objToAdopt, id, TRUE, status);
    816 }
    817 
    818 URegistryKey
    819 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
    820 {
    821     ICUServiceKey* key = createKey(&id, status);
    822     if (key != NULL) {
    823         UnicodeString canonicalID;
    824         key->canonicalID(canonicalID);
    825         delete key;
    826 
    827         ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status);
    828         if (f != NULL) {
    829             return registerFactory(f, status);
    830         }
    831     }
    832     delete objToAdopt;
    833     return NULL;
    834 }
    835 
    836 ICUServiceFactory*
    837 ICUService::createSimpleFactory(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
    838 {
    839     if (U_SUCCESS(status)) {
    840         if ((objToAdopt != NULL) && (!id.isBogus())) {
    841             return new SimpleFactory(objToAdopt, id, visible);
    842         }
    843         status = U_ILLEGAL_ARGUMENT_ERROR;
    844     }
    845     return NULL;
    846 }
    847 
    848 URegistryKey
    849 ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status)
    850 {
    851     if (U_SUCCESS(status) && factoryToAdopt != NULL) {
    852         Mutex mutex(&lock);
    853 
    854         if (factories == NULL) {
    855             factories = new UVector(deleteUObject, NULL, status);
    856             if (U_FAILURE(status)) {
    857                 delete factories;
    858                 return NULL;
    859             }
    860         }
    861         factories->insertElementAt(factoryToAdopt, 0, status);
    862         if (U_SUCCESS(status)) {
    863             clearCaches();
    864         } else {
    865             delete factoryToAdopt;
    866             factoryToAdopt = NULL;
    867         }
    868     }
    869 
    870     if (factoryToAdopt != NULL) {
    871         notifyChanged();
    872     }
    873 
    874     return (URegistryKey)factoryToAdopt;
    875 }
    876 
    877 UBool
    878 ICUService::unregister(URegistryKey rkey, UErrorCode& status)
    879 {
    880     ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
    881     UBool result = FALSE;
    882     if (factory != NULL && factories != NULL) {
    883         Mutex mutex(&lock);
    884 
    885         if (factories->removeElement(factory)) {
    886             clearCaches();
    887             result = TRUE;
    888         } else {
    889             status = U_ILLEGAL_ARGUMENT_ERROR;
    890             delete factory;
    891         }
    892     }
    893     if (result) {
    894         notifyChanged();
    895     }
    896     return result;
    897 }
    898 
    899 void
    900 ICUService::reset()
    901 {
    902     {
    903         Mutex mutex(&lock);
    904         reInitializeFactories();
    905         clearCaches();
    906     }
    907     notifyChanged();
    908 }
    909 
    910 void
    911 ICUService::reInitializeFactories()
    912 {
    913     if (factories != NULL) {
    914         factories->removeAllElements();
    915     }
    916 }
    917 
    918 UBool
    919 ICUService::isDefault() const
    920 {
    921     return countFactories() == 0;
    922 }
    923 
    924 ICUServiceKey*
    925 ICUService::createKey(const UnicodeString* id, UErrorCode& status) const
    926 {
    927     return (U_FAILURE(status) || id == NULL) ? NULL : new ICUServiceKey(*id);
    928 }
    929 
    930 void
    931 ICUService::clearCaches()
    932 {
    933     // callers synchronize before use
    934     ++timestamp;
    935     delete dnCache;
    936     dnCache = NULL;
    937     delete idCache;
    938     idCache = NULL;
    939     delete serviceCache; serviceCache = NULL;
    940 }
    941 
    942 void
    943 ICUService::clearServiceCache()
    944 {
    945     // callers synchronize before use
    946     delete serviceCache; serviceCache = NULL;
    947 }
    948 
    949 UBool
    950 ICUService::acceptsListener(const EventListener& l) const
    951 {
    952     return dynamic_cast<const ServiceListener*>(&l) != NULL;
    953 }
    954 
    955 void
    956 ICUService::notifyListener(EventListener& l) const
    957 {
    958     ((ServiceListener&)l).serviceChanged(*this);
    959 }
    960 
    961 UnicodeString&
    962 ICUService::getName(UnicodeString& result) const
    963 {
    964     return result.append(name);
    965 }
    966 
    967 int32_t
    968 ICUService::countFactories() const
    969 {
    970     return factories == NULL ? 0 : factories->size();
    971 }
    972 
    973 int32_t
    974 ICUService::getTimestamp() const
    975 {
    976     return timestamp;
    977 }
    978 
    979 U_NAMESPACE_END
    980 
    981 /* UCONFIG_NO_SERVICE */
    982 #endif
    983