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