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 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 330static UMTX lock; 331 332ICUService::ICUService() 333: name() 334, timestamp(0) 335, factories(NULL) 336, serviceCache(NULL) 337, idCache(NULL) 338, dnCache(NULL) 339{ 340} 341 342ICUService::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 352ICUService::~ICUService() 353{ 354 { 355 Mutex mutex(&lock); 356 clearCaches(); 357 delete factories; 358 factories = NULL; 359 } 360} 361 362UObject* 363ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const 364{ 365 return get(descriptor, NULL, status); 366} 367 368UObject* 369ICUService::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 380UObject* 381ICUService::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 389UObject* 390ICUService::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. 398class XMutex : public UMemory { 399public: 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 410private: 411 UMTX *fMutex; 412 UBool fActive; 413}; 414 415struct UVectorDeleter { 416 UVector* _obj; 417 UVectorDeleter() : _obj(NULL) {} 418 ~UVectorDeleter() { delete _obj; } 419}; 420 421// called only by factories, treat as private 422UObject* 423ICUService::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()); 538outerEnd: 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 592UObject* 593ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const 594{ 595 return NULL; 596} 597 598UVector& 599ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const { 600 return getVisibleIDs(result, NULL, status); 601} 602 603UVector& 604ICUService::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 652const Hashtable* 653ICUService::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 679UnicodeString& 680ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const 681{ 682 return getDisplayName(id, result, Locale::getDefault()); 683} 684 685UnicodeString& 686ICUService::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 719UVector& 720ICUService::getDisplayNames(UVector& result, UErrorCode& status) const 721{ 722 return getDisplayNames(result, Locale::getDefault(), NULL, status); 723} 724 725 726UVector& 727ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const 728{ 729 return getDisplayNames(result, locale, NULL, status); 730} 731 732UVector& 733ICUService::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 806URegistryKey 807ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status) 808{ 809 return registerInstance(objToAdopt, id, TRUE, status); 810} 811 812URegistryKey 813ICUService::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 830ICUServiceFactory* 831ICUService::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 842URegistryKey 843ICUService::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 871UBool 872ICUService::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 893void 894ICUService::reset() 895{ 896 { 897 Mutex mutex(&lock); 898 reInitializeFactories(); 899 clearCaches(); 900 } 901 notifyChanged(); 902} 903 904void 905ICUService::reInitializeFactories() 906{ 907 if (factories != NULL) { 908 factories->removeAllElements(); 909 } 910} 911 912UBool 913ICUService::isDefault() const 914{ 915 return countFactories() == 0; 916} 917 918ICUServiceKey* 919ICUService::createKey(const UnicodeString* id, UErrorCode& status) const 920{ 921 return (U_FAILURE(status) || id == NULL) ? NULL : new ICUServiceKey(*id); 922} 923 924void 925ICUService::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 936void 937ICUService::clearServiceCache() 938{ 939 // callers synchronize before use 940 delete serviceCache; serviceCache = NULL; 941} 942 943UBool 944ICUService::acceptsListener(const EventListener& l) const 945{ 946 return dynamic_cast<const ServiceListener*>(&l) != NULL; 947} 948 949void 950ICUService::notifyListener(EventListener& l) const 951{ 952 ((ServiceListener&)l).serviceChanged(*this); 953} 954 955UnicodeString& 956ICUService::getName(UnicodeString& result) const 957{ 958 return result.append(name); 959} 960 961int32_t 962ICUService::countFactories() const 963{ 964 return factories == NULL ? 0 : factories->size(); 965} 966 967int32_t 968ICUService::getTimestamp() const 969{ 970 return timestamp; 971} 972 973U_NAMESPACE_END 974 975/* UCONFIG_NO_SERVICE */ 976#endif 977