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