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