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