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