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 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 return NULL; 551 } 552 553 if (cacheDescriptorList._obj != NULL) { 554 for (int32_t i = cacheDescriptorList._obj->size(); --i >= 0;) { 555 UnicodeString* desc = (UnicodeString*)cacheDescriptorList._obj->elementAt(i); 556 557 serviceCache->put(*desc, result, status); 558 if (U_FAILURE(status)) { 559 return NULL; 560 } 561 562 result->ref(); 563 cacheDescriptorList._obj->removeElementAt(i); 564 } 565 } 566 } 567 568 if (actualReturn != NULL) { 569 // strip null prefix 570 if (result->actualDescriptor.indexOf((UChar)0x2f) == 0) { // U+002f=slash (/) 571 actualReturn->remove(); 572 actualReturn->append(result->actualDescriptor, 573 1, 574 result->actualDescriptor.length() - 1); 575 } else { 576 *actualReturn = result->actualDescriptor; 577 } 578 579 if (actualReturn->isBogus()) { 580 status = U_MEMORY_ALLOCATION_ERROR; 581 delete result; 582 return NULL; 583 } 584 } 585 586 UObject* service = cloneInstance(result->service); 587 if (putInCache && !cacheResult) { 588 delete result; 589 } 590 return service; 591 } 592 } 593 594 return handleDefault(key, actualReturn, status); 595 } 596 597 UObject* 598 ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const 599 { 600 return NULL; 601 } 602 603 UVector& 604 ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const { 605 return getVisibleIDs(result, NULL, status); 606 } 607 608 UVector& 609 ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const 610 { 611 result.removeAllElements(); 612 613 if (U_FAILURE(status)) { 614 return result; 615 } 616 617 { 618 Mutex mutex(&lock); 619 const Hashtable* map = getVisibleIDMap(status); 620 if (map != NULL) { 621 ICUServiceKey* fallbackKey = createKey(matchID, status); 622 623 for (int32_t pos = UHASH_FIRST;;) { 624 const UHashElement* e = map->nextElement(pos); 625 if (e == NULL) { 626 break; 627 } 628 629 const UnicodeString* id = (const UnicodeString*)e->key.pointer; 630 if (fallbackKey != NULL) { 631 if (!fallbackKey->isFallbackOf(*id)) { 632 continue; 633 } 634 } 635 636 UnicodeString* idClone = new UnicodeString(*id); 637 if (idClone == NULL || idClone->isBogus()) { 638 delete idClone; 639 status = U_MEMORY_ALLOCATION_ERROR; 640 break; 641 } 642 result.addElement(idClone, status); 643 if (U_FAILURE(status)) { 644 delete idClone; 645 break; 646 } 647 } 648 delete fallbackKey; 649 } 650 } 651 if (U_FAILURE(status)) { 652 result.removeAllElements(); 653 } 654 return result; 655 } 656 657 const Hashtable* 658 ICUService::getVisibleIDMap(UErrorCode& status) const { 659 if (U_FAILURE(status)) return NULL; 660 661 // must only be called when lock is already held 662 663 ICUService* ncthis = (ICUService*)this; // cast away semantic const 664 if (idCache == NULL) { 665 ncthis->idCache = new Hashtable(status); 666 if (idCache == NULL) { 667 status = U_MEMORY_ALLOCATION_ERROR; 668 } else if (factories != NULL) { 669 for (int32_t pos = factories->size(); --pos >= 0;) { 670 ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(pos); 671 f->updateVisibleIDs(*idCache, status); 672 } 673 if (U_FAILURE(status)) { 674 delete idCache; 675 ncthis->idCache = NULL; 676 } 677 } 678 } 679 680 return idCache; 681 } 682 683 684 UnicodeString& 685 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const 686 { 687 return getDisplayName(id, result, Locale::getDefault()); 688 } 689 690 UnicodeString& 691 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const 692 { 693 { 694 UErrorCode status = U_ZERO_ERROR; 695 Mutex mutex(&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 status = U_ZERO_ERROR; 706 ICUServiceKey* fallbackKey = createKey(&id, status); 707 while (fallbackKey != NULL && 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 724 UVector& 725 ICUService::getDisplayNames(UVector& result, UErrorCode& status) const 726 { 727 return getDisplayNames(result, Locale::getDefault(), NULL, status); 728 } 729 730 731 UVector& 732 ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const 733 { 734 return getDisplayNames(result, locale, NULL, status); 735 } 736 737 UVector& 738 ICUService::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(&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 (U_FAILURE(status)) { 757 return result; 758 } 759 ncthis->dnCache = new DNCache(locale); 760 if (dnCache == NULL) { 761 status = U_MEMORY_ALLOCATION_ERROR; 762 return result; 763 } 764 765 int32_t pos = UHASH_FIRST; 766 const UHashElement* entry = NULL; 767 while ((entry = m->nextElement(pos)) != NULL) { 768 const UnicodeString* id = (const UnicodeString*)entry->key.pointer; 769 ICUServiceFactory* f = (ICUServiceFactory*)entry->value.pointer; 770 UnicodeString dname; 771 f->getDisplayName(*id, locale, dname); 772 if (dname.isBogus()) { 773 status = U_MEMORY_ALLOCATION_ERROR; 774 } else { 775 dnCache->cache.put(dname, (void*)id, status); // share pointer with visibleIDMap 776 if (U_SUCCESS(status)) { 777 continue; 778 } 779 } 780 delete dnCache; 781 ncthis->dnCache = NULL; 782 return result; 783 } 784 } 785 } 786 787 ICUServiceKey* matchKey = createKey(matchID, status); 788 /* To ensure that all elements in the hashtable are iterated, set pos to -1. 789 * nextElement(pos) will skip the position at pos and begin the iteration 790 * at the next position, which in this case will be 0. 791 */ 792 int32_t pos = UHASH_FIRST; 793 const UHashElement *entry = NULL; 794 while ((entry = dnCache->cache.nextElement(pos)) != NULL) { 795 const UnicodeString* id = (const UnicodeString*)entry->value.pointer; 796 if (matchKey != NULL && !matchKey->isFallbackOf(*id)) { 797 continue; 798 } 799 const UnicodeString* dn = (const UnicodeString*)entry->key.pointer; 800 StringPair* sp = StringPair::create(*id, *dn, status); 801 result.addElement(sp, status); 802 if (U_FAILURE(status)) { 803 result.removeAllElements(); 804 break; 805 } 806 } 807 delete matchKey; 808 809 return result; 810 } 811 812 URegistryKey 813 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status) 814 { 815 return registerInstance(objToAdopt, id, TRUE, status); 816 } 817 818 URegistryKey 819 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status) 820 { 821 ICUServiceKey* key = createKey(&id, status); 822 if (key != NULL) { 823 UnicodeString canonicalID; 824 key->canonicalID(canonicalID); 825 delete key; 826 827 ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status); 828 if (f != NULL) { 829 return registerFactory(f, status); 830 } 831 } 832 delete objToAdopt; 833 return NULL; 834 } 835 836 ICUServiceFactory* 837 ICUService::createSimpleFactory(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status) 838 { 839 if (U_SUCCESS(status)) { 840 if ((objToAdopt != NULL) && (!id.isBogus())) { 841 return new SimpleFactory(objToAdopt, id, visible); 842 } 843 status = U_ILLEGAL_ARGUMENT_ERROR; 844 } 845 return NULL; 846 } 847 848 URegistryKey 849 ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status) 850 { 851 if (U_SUCCESS(status) && factoryToAdopt != NULL) { 852 Mutex mutex(&lock); 853 854 if (factories == NULL) { 855 factories = new UVector(deleteUObject, NULL, status); 856 if (U_FAILURE(status)) { 857 delete factories; 858 return NULL; 859 } 860 } 861 factories->insertElementAt(factoryToAdopt, 0, status); 862 if (U_SUCCESS(status)) { 863 clearCaches(); 864 } else { 865 delete factoryToAdopt; 866 factoryToAdopt = NULL; 867 } 868 } 869 870 if (factoryToAdopt != NULL) { 871 notifyChanged(); 872 } 873 874 return (URegistryKey)factoryToAdopt; 875 } 876 877 UBool 878 ICUService::unregister(URegistryKey rkey, UErrorCode& status) 879 { 880 ICUServiceFactory *factory = (ICUServiceFactory*)rkey; 881 UBool result = FALSE; 882 if (factory != NULL && factories != NULL) { 883 Mutex mutex(&lock); 884 885 if (factories->removeElement(factory)) { 886 clearCaches(); 887 result = TRUE; 888 } else { 889 status = U_ILLEGAL_ARGUMENT_ERROR; 890 delete factory; 891 } 892 } 893 if (result) { 894 notifyChanged(); 895 } 896 return result; 897 } 898 899 void 900 ICUService::reset() 901 { 902 { 903 Mutex mutex(&lock); 904 reInitializeFactories(); 905 clearCaches(); 906 } 907 notifyChanged(); 908 } 909 910 void 911 ICUService::reInitializeFactories() 912 { 913 if (factories != NULL) { 914 factories->removeAllElements(); 915 } 916 } 917 918 UBool 919 ICUService::isDefault() const 920 { 921 return countFactories() == 0; 922 } 923 924 ICUServiceKey* 925 ICUService::createKey(const UnicodeString* id, UErrorCode& status) const 926 { 927 return (U_FAILURE(status) || id == NULL) ? NULL : new ICUServiceKey(*id); 928 } 929 930 void 931 ICUService::clearCaches() 932 { 933 // callers synchronize before use 934 ++timestamp; 935 delete dnCache; 936 dnCache = NULL; 937 delete idCache; 938 idCache = NULL; 939 delete serviceCache; serviceCache = NULL; 940 } 941 942 void 943 ICUService::clearServiceCache() 944 { 945 // callers synchronize before use 946 delete serviceCache; serviceCache = NULL; 947 } 948 949 UBool 950 ICUService::acceptsListener(const EventListener& l) const 951 { 952 return dynamic_cast<const ServiceListener*>(&l) != NULL; 953 } 954 955 void 956 ICUService::notifyListener(EventListener& l) const 957 { 958 ((ServiceListener&)l).serviceChanged(*this); 959 } 960 961 UnicodeString& 962 ICUService::getName(UnicodeString& result) const 963 { 964 return result.append(name); 965 } 966 967 int32_t 968 ICUService::countFactories() const 969 { 970 return factories == NULL ? 0 : factories->size(); 971 } 972 973 int32_t 974 ICUService::getTimestamp() const 975 { 976 return timestamp; 977 } 978 979 U_NAMESPACE_END 980 981 /* UCONFIG_NO_SERVICE */ 982 #endif 983