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                     delete result;
    551                     return NULL;
    552                 }
    553 
    554                 if (cacheDescriptorList._obj != NULL) {
    555                     for (int32_t i = cacheDescriptorList._obj->size(); --i >= 0;) {
    556                         UnicodeString* desc = (UnicodeString*)cacheDescriptorList._obj->elementAt(i);
    557                         serviceCache->put(*desc, result, status);
    558                         if (U_FAILURE(status)) {
    559                             delete result;
    560                             return NULL;
    561                         }
    562 
    563                         result->ref();
    564                         cacheDescriptorList._obj->removeElementAt(i);
    565                     }
    566                 }
    567             }
    568 
    569             if (actualReturn != NULL) {
    570                 // strip null prefix
    571                 if (result->actualDescriptor.indexOf((UChar)0x2f) == 0) { // U+002f=slash (/)
    572                     actualReturn->remove();
    573                     actualReturn->append(result->actualDescriptor,
    574                         1,
    575                         result->actualDescriptor.length() - 1);
    576                 } else {
    577                     *actualReturn = result->actualDescriptor;
    578                 }
    579 
    580                 if (actualReturn->isBogus()) {
    581                     status = U_MEMORY_ALLOCATION_ERROR;
    582                     delete result;
    583                     return NULL;
    584                 }
    585             }
    586 
    587             UObject* service = cloneInstance(result->service);
    588             if (putInCache && !cacheResult) {
    589                 delete result;
    590             }
    591             return service;
    592         }
    593     }
    594 
    595     return handleDefault(key, actualReturn, status);
    596 }
    597 
    598 UObject*
    599 ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const
    600 {
    601     return NULL;
    602 }
    603 
    604 UVector&
    605 ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const {
    606     return getVisibleIDs(result, NULL, status);
    607 }
    608 
    609 UVector&
    610 ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const
    611 {
    612     result.removeAllElements();
    613 
    614     if (U_FAILURE(status)) {
    615         return result;
    616     }
    617 
    618     {
    619         Mutex mutex(&lock);
    620         const Hashtable* map = getVisibleIDMap(status);
    621         if (map != NULL) {
    622             ICUServiceKey* fallbackKey = createKey(matchID, status);
    623 
    624             for (int32_t pos = UHASH_FIRST;;) {
    625                 const UHashElement* e = map->nextElement(pos);
    626                 if (e == NULL) {
    627                     break;
    628                 }
    629 
    630                 const UnicodeString* id = (const UnicodeString*)e->key.pointer;
    631                 if (fallbackKey != NULL) {
    632                     if (!fallbackKey->isFallbackOf(*id)) {
    633                         continue;
    634                     }
    635                 }
    636 
    637                 UnicodeString* idClone = new UnicodeString(*id);
    638                 if (idClone == NULL || idClone->isBogus()) {
    639                     delete idClone;
    640                     status = U_MEMORY_ALLOCATION_ERROR;
    641                     break;
    642                 }
    643                 result.addElement(idClone, status);
    644                 if (U_FAILURE(status)) {
    645                     delete idClone;
    646                     break;
    647                 }
    648             }
    649             delete fallbackKey;
    650         }
    651     }
    652     if (U_FAILURE(status)) {
    653         result.removeAllElements();
    654     }
    655     return result;
    656 }
    657 
    658 const Hashtable*
    659 ICUService::getVisibleIDMap(UErrorCode& status) const {
    660     if (U_FAILURE(status)) return NULL;
    661 
    662     // must only be called when lock is already held
    663 
    664     ICUService* ncthis = (ICUService*)this; // cast away semantic const
    665     if (idCache == NULL) {
    666         ncthis->idCache = new Hashtable(status);
    667         if (idCache == NULL) {
    668             status = U_MEMORY_ALLOCATION_ERROR;
    669         } else if (factories != NULL) {
    670             for (int32_t pos = factories->size(); --pos >= 0;) {
    671                 ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(pos);
    672                 f->updateVisibleIDs(*idCache, status);
    673             }
    674             if (U_FAILURE(status)) {
    675                 delete idCache;
    676                 ncthis->idCache = NULL;
    677             }
    678         }
    679     }
    680 
    681     return idCache;
    682 }
    683 
    684 
    685 UnicodeString&
    686 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const
    687 {
    688     return getDisplayName(id, result, Locale::getDefault());
    689 }
    690 
    691 UnicodeString&
    692 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const
    693 {
    694     {
    695         UErrorCode status = U_ZERO_ERROR;
    696         Mutex mutex(&lock);
    697         const Hashtable* map = getVisibleIDMap(status);
    698         if (map != NULL) {
    699             ICUServiceFactory* f = (ICUServiceFactory*)map->get(id);
    700             if (f != NULL) {
    701                 f->getDisplayName(id, locale, result);
    702                 return result;
    703             }
    704 
    705             // fallback
    706             UErrorCode status = U_ZERO_ERROR;
    707             ICUServiceKey* fallbackKey = createKey(&id, status);
    708             while (fallbackKey->fallback()) {
    709                 UnicodeString us;
    710                 fallbackKey->currentID(us);
    711                 f = (ICUServiceFactory*)map->get(us);
    712                 if (f != NULL) {
    713                     f->getDisplayName(id, locale, result);
    714                     delete fallbackKey;
    715                     return result;
    716                 }
    717             }
    718             delete fallbackKey;
    719         }
    720     }
    721     result.setToBogus();
    722     return result;
    723 }
    724 
    725 UVector&
    726 ICUService::getDisplayNames(UVector& result, UErrorCode& status) const
    727 {
    728     return getDisplayNames(result, Locale::getDefault(), NULL, status);
    729 }
    730 
    731 
    732 UVector&
    733 ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const
    734 {
    735     return getDisplayNames(result, locale, NULL, status);
    736 }
    737 
    738 UVector&
    739 ICUService::getDisplayNames(UVector& result,
    740                             const Locale& locale,
    741                             const UnicodeString* matchID,
    742                             UErrorCode& status) const
    743 {
    744     result.removeAllElements();
    745     result.setDeleter(userv_deleteStringPair);
    746     if (U_SUCCESS(status)) {
    747         ICUService* ncthis = (ICUService*)this; // cast away semantic const
    748         Mutex mutex(&lock);
    749 
    750         if (dnCache != NULL && dnCache->locale != locale) {
    751             delete dnCache;
    752             ncthis->dnCache = NULL;
    753         }
    754 
    755         if (dnCache == NULL) {
    756             const Hashtable* m = getVisibleIDMap(status);
    757             if (U_FAILURE(status)) {
    758                 return result;
    759             }
    760             ncthis->dnCache = new DNCache(locale);
    761             if (dnCache == NULL) {
    762                 status = U_MEMORY_ALLOCATION_ERROR;
    763                 return result;
    764             }
    765 
    766             int32_t pos = UHASH_FIRST;
    767             const UHashElement* entry = NULL;
    768             while ((entry = m->nextElement(pos)) != NULL) {
    769                 const UnicodeString* id = (const UnicodeString*)entry->key.pointer;
    770                 ICUServiceFactory* f = (ICUServiceFactory*)entry->value.pointer;
    771                 UnicodeString dname;
    772                 f->getDisplayName(*id, locale, dname);
    773                 if (dname.isBogus()) {
    774                     status = U_MEMORY_ALLOCATION_ERROR;
    775                 } else {
    776                     dnCache->cache.put(dname, (void*)id, status); // share pointer with visibleIDMap
    777                     if (U_SUCCESS(status)) {
    778                         continue;
    779                     }
    780                 }
    781                 delete dnCache;
    782                 ncthis->dnCache = NULL;
    783                 return result;
    784             }
    785         }
    786     }
    787 
    788     ICUServiceKey* matchKey = createKey(matchID, status);
    789     /* To ensure that all elements in the hashtable are iterated, set pos to -1.
    790      * nextElement(pos) will skip the position at pos and begin the iteration
    791      * at the next position, which in this case will be 0.
    792      */
    793     int32_t pos = UHASH_FIRST;
    794     const UHashElement *entry = NULL;
    795     while ((entry = dnCache->cache.nextElement(pos)) != NULL) {
    796         const UnicodeString* id = (const UnicodeString*)entry->value.pointer;
    797         if (matchKey != NULL && !matchKey->isFallbackOf(*id)) {
    798             continue;
    799         }
    800         const UnicodeString* dn = (const UnicodeString*)entry->key.pointer;
    801         StringPair* sp = StringPair::create(*id, *dn, status);
    802         result.addElement(sp, status);
    803         if (U_FAILURE(status)) {
    804             result.removeAllElements();
    805             break;
    806         }
    807     }
    808     delete matchKey;
    809 
    810     return result;
    811 }
    812 
    813 URegistryKey
    814 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status)
    815 {
    816     return registerInstance(objToAdopt, id, TRUE, status);
    817 }
    818 
    819 URegistryKey
    820 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
    821 {
    822     ICUServiceKey* key = createKey(&id, status);
    823     if (key != NULL) {
    824         UnicodeString canonicalID;
    825         key->canonicalID(canonicalID);
    826         delete key;
    827 
    828         ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status);
    829         if (f != NULL) {
    830             return registerFactory(f, status);
    831         }
    832     }
    833     delete objToAdopt;
    834     return NULL;
    835 }
    836 
    837 ICUServiceFactory*
    838 ICUService::createSimpleFactory(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
    839 {
    840     if (U_SUCCESS(status)) {
    841         if ((objToAdopt != NULL) && (!id.isBogus())) {
    842             return new SimpleFactory(objToAdopt, id, visible);
    843         }
    844         status = U_ILLEGAL_ARGUMENT_ERROR;
    845     }
    846     return NULL;
    847 }
    848 
    849 URegistryKey
    850 ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status)
    851 {
    852     if (U_SUCCESS(status) && factoryToAdopt != NULL) {
    853         Mutex mutex(&lock);
    854 
    855         if (factories == NULL) {
    856             factories = new UVector(deleteUObject, NULL, status);
    857             if (U_FAILURE(status)) {
    858                 delete factories;
    859                 return NULL;
    860             }
    861         }
    862         factories->insertElementAt(factoryToAdopt, 0, status);
    863         if (U_SUCCESS(status)) {
    864             clearCaches();
    865         } else {
    866             delete factoryToAdopt;
    867             factoryToAdopt = NULL;
    868         }
    869     }
    870 
    871     if (factoryToAdopt != NULL) {
    872         notifyChanged();
    873     }
    874 
    875     return (URegistryKey)factoryToAdopt;
    876 }
    877 
    878 UBool
    879 ICUService::unregister(URegistryKey rkey, UErrorCode& status)
    880 {
    881     ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
    882     UBool result = FALSE;
    883     if (factory != NULL && factories != NULL) {
    884         Mutex mutex(&lock);
    885 
    886         if (factories->removeElement(factory)) {
    887             clearCaches();
    888             result = TRUE;
    889         } else {
    890             status = U_ILLEGAL_ARGUMENT_ERROR;
    891             delete factory;
    892         }
    893     }
    894     if (result) {
    895         notifyChanged();
    896     }
    897     return result;
    898 }
    899 
    900 void
    901 ICUService::reset()
    902 {
    903     {
    904         Mutex mutex(&lock);
    905         reInitializeFactories();
    906         clearCaches();
    907     }
    908     notifyChanged();
    909 }
    910 
    911 void
    912 ICUService::reInitializeFactories()
    913 {
    914     if (factories != NULL) {
    915         factories->removeAllElements();
    916     }
    917 }
    918 
    919 UBool
    920 ICUService::isDefault() const
    921 {
    922     return countFactories() == 0;
    923 }
    924 
    925 ICUServiceKey*
    926 ICUService::createKey(const UnicodeString* id, UErrorCode& status) const
    927 {
    928     return (U_FAILURE(status) || id == NULL) ? NULL : new ICUServiceKey(*id);
    929 }
    930 
    931 void
    932 ICUService::clearCaches()
    933 {
    934     // callers synchronize before use
    935     ++timestamp;
    936     delete dnCache;
    937     dnCache = NULL;
    938     delete idCache;
    939     idCache = NULL;
    940     delete serviceCache; serviceCache = NULL;
    941 }
    942 
    943 void
    944 ICUService::clearServiceCache()
    945 {
    946     // callers synchronize before use
    947     delete serviceCache; serviceCache = NULL;
    948 }
    949 
    950 UBool
    951 ICUService::acceptsListener(const EventListener& l) const
    952 {
    953     return dynamic_cast<const ServiceListener*>(&l) != NULL;
    954 }
    955 
    956 void
    957 ICUService::notifyListener(EventListener& l) const
    958 {
    959     ((ServiceListener&)l).serviceChanged(*this);
    960 }
    961 
    962 UnicodeString&
    963 ICUService::getName(UnicodeString& result) const
    964 {
    965     return result.append(name);
    966 }
    967 
    968 int32_t
    969 ICUService::countFactories() const
    970 {
    971     return factories == NULL ? 0 : factories->size();
    972 }
    973 
    974 int32_t
    975 ICUService::getTimestamp() const
    976 {
    977     return timestamp;
    978 }
    979 
    980 U_NAMESPACE_END
    981 
    982 /* UCONFIG_NO_SERVICE */
    983 #endif
    984