]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/serv.cpp
ICU-64232.0.1.tar.gz
[apple/icu.git] / icuSources / common / serv.cpp
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() {
337 static UMutex *m = STATIC_NEW(UMutex);
338 return m;
339 }
340
341 ICUService::ICUService()
342 : name()
343 , timestamp(0)
344 , factories(NULL)
345 , serviceCache(NULL)
346 , idCache(NULL)
347 , dnCache(NULL)
348 {
349 }
350
351 ICUService::ICUService(const UnicodeString& newName)
352 : name(newName)
353 , timestamp(0)
354 , factories(NULL)
355 , serviceCache(NULL)
356 , idCache(NULL)
357 , dnCache(NULL)
358 {
359 }
360
361 ICUService::~ICUService()
362 {
363 {
364 Mutex mutex(lock());
365 clearCaches();
366 delete factories;
367 factories = NULL;
368 }
369 }
370
371 UObject*
372 ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const
373 {
374 return get(descriptor, NULL, status);
375 }
376
377 UObject*
378 ICUService::get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const
379 {
380 UObject* result = NULL;
381 ICUServiceKey* key = createKey(&descriptor, status);
382 if (key) {
383 result = getKey(*key, actualReturn, status);
384 delete key;
385 }
386 return result;
387 }
388
389 UObject*
390 ICUService::getKey(ICUServiceKey& key, UErrorCode& status) const
391 {
392 return getKey(key, NULL, status);
393 }
394
395 // this is a vector that subclasses of ICUService can override to further customize the result object
396 // before returning it. All other public get functions should call this one.
397
398 UObject*
399 ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const
400 {
401 return getKey(key, actualReturn, NULL, status);
402 }
403
404 // make it possible to call reentrantly on systems that don't have reentrant mutexes.
405 // we can use this simple approach since we know the situation where we're calling
406 // reentrantly even without knowing the thread.
407 class XMutex : public UMemory {
408 public:
409 inline XMutex(UMutex *mutex, UBool reentering)
410 : fMutex(mutex)
411 , fActive(!reentering)
412 {
413 if (fActive) umtx_lock(fMutex);
414 }
415 inline ~XMutex() {
416 if (fActive) umtx_unlock(fMutex);
417 }
418
419 private:
420 UMutex *fMutex;
421 UBool fActive;
422 };
423
424 struct UVectorDeleter {
425 UVector* _obj;
426 UVectorDeleter() : _obj(NULL) {}
427 ~UVectorDeleter() { delete _obj; }
428 };
429
430 // called only by factories, treat as private
431 UObject*
432 ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUServiceFactory* factory, UErrorCode& status) const
433 {
434 if (U_FAILURE(status)) {
435 return NULL;
436 }
437
438 if (isDefault()) {
439 return handleDefault(key, actualReturn, status);
440 }
441
442 ICUService* ncthis = (ICUService*)this; // cast away semantic const
443
444 CacheEntry* result = NULL;
445 {
446 // The factory list can't be modified until we're done,
447 // otherwise we might update the cache with an invalid result.
448 // The cache has to stay in synch with the factory list.
449 // ICU doesn't have monitors so we can't use rw locks, so
450 // we single-thread everything using this service, for now.
451
452 // if factory is not null, we're calling from within the mutex,
453 // and since some unix machines don't have reentrant mutexes we
454 // need to make sure not to try to lock it again.
455 XMutex mutex(lock(), factory != NULL);
456
457 if (serviceCache == NULL) {
458 ncthis->serviceCache = new Hashtable(status);
459 if (ncthis->serviceCache == NULL) {
460 return NULL;
461 }
462 if (U_FAILURE(status)) {
463 delete serviceCache;
464 return NULL;
465 }
466 serviceCache->setValueDeleter(cacheDeleter);
467 }
468
469 UnicodeString currentDescriptor;
470 UVectorDeleter cacheDescriptorList;
471 UBool putInCache = FALSE;
472
473 int32_t startIndex = 0;
474 int32_t limit = factories->size();
475 UBool cacheResult = TRUE;
476
477 if (factory != NULL) {
478 for (int32_t i = 0; i < limit; ++i) {
479 if (factory == (const ICUServiceFactory*)factories->elementAt(i)) {
480 startIndex = i + 1;
481 break;
482 }
483 }
484 if (startIndex == 0) {
485 // throw new InternalError("Factory " + factory + "not registered with service: " + this);
486 status = U_ILLEGAL_ARGUMENT_ERROR;
487 return NULL;
488 }
489 cacheResult = FALSE;
490 }
491
492 do {
493 currentDescriptor.remove();
494 key.currentDescriptor(currentDescriptor);
495 result = (CacheEntry*)serviceCache->get(currentDescriptor);
496 if (result != NULL) {
497 break;
498 }
499
500 // first test of cache failed, so we'll have to update
501 // the cache if we eventually succeed-- that is, if we're
502 // going to update the cache at all.
503 putInCache = TRUE;
504
505 int32_t index = startIndex;
506 while (index < limit) {
507 ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(index++);
508 UObject* service = f->create(key, this, status);
509 if (U_FAILURE(status)) {
510 delete service;
511 return NULL;
512 }
513 if (service != NULL) {
514 result = new CacheEntry(currentDescriptor, service);
515 if (result == NULL) {
516 delete service;
517 status = U_MEMORY_ALLOCATION_ERROR;
518 return NULL;
519 }
520
521 goto outerEnd;
522 }
523 }
524
525 // prepare to load the cache with all additional ids that
526 // will resolve to result, assuming we'll succeed. We
527 // don't want to keep querying on an id that's going to
528 // fallback to the one that succeeded, we want to hit the
529 // cache the first time next goaround.
530 if (cacheDescriptorList._obj == NULL) {
531 cacheDescriptorList._obj = new UVector(uprv_deleteUObject, NULL, 5, status);
532 if (U_FAILURE(status)) {
533 return NULL;
534 }
535 }
536 UnicodeString* idToCache = new UnicodeString(currentDescriptor);
537 if (idToCache == NULL || idToCache->isBogus()) {
538 status = U_MEMORY_ALLOCATION_ERROR;
539 return NULL;
540 }
541
542 cacheDescriptorList._obj->addElement(idToCache, status);
543 if (U_FAILURE(status)) {
544 return NULL;
545 }
546 } while (key.fallback());
547 outerEnd:
548
549 if (result != NULL) {
550 if (putInCache && cacheResult) {
551 serviceCache->put(result->actualDescriptor, result, status);
552 if (U_FAILURE(status)) {
553 return NULL;
554 }
555
556 if (cacheDescriptorList._obj != NULL) {
557 for (int32_t i = cacheDescriptorList._obj->size(); --i >= 0;) {
558 UnicodeString* desc = (UnicodeString*)cacheDescriptorList._obj->elementAt(i);
559
560 serviceCache->put(*desc, result, status);
561 if (U_FAILURE(status)) {
562 return NULL;
563 }
564
565 result->ref();
566 cacheDescriptorList._obj->removeElementAt(i);
567 }
568 }
569 }
570
571 if (actualReturn != NULL) {
572 // strip null prefix
573 if (result->actualDescriptor.indexOf((UChar)0x2f) == 0) { // U+002f=slash (/)
574 actualReturn->remove();
575 actualReturn->append(result->actualDescriptor,
576 1,
577 result->actualDescriptor.length() - 1);
578 } else {
579 *actualReturn = result->actualDescriptor;
580 }
581
582 if (actualReturn->isBogus()) {
583 status = U_MEMORY_ALLOCATION_ERROR;
584 delete result;
585 return NULL;
586 }
587 }
588
589 UObject* service = cloneInstance(result->service);
590 if (putInCache && !cacheResult) {
591 delete result;
592 }
593 return service;
594 }
595 }
596
597 return handleDefault(key, actualReturn, status);
598 }
599
600 UObject*
601 ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const
602 {
603 return NULL;
604 }
605
606 UVector&
607 ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const {
608 return getVisibleIDs(result, NULL, status);
609 }
610
611 UVector&
612 ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const
613 {
614 result.removeAllElements();
615
616 if (U_FAILURE(status)) {
617 return result;
618 }
619
620 {
621 Mutex mutex(lock());
622 const Hashtable* map = getVisibleIDMap(status);
623 if (map != NULL) {
624 ICUServiceKey* fallbackKey = createKey(matchID, status);
625
626 for (int32_t pos = UHASH_FIRST;;) {
627 const UHashElement* e = map->nextElement(pos);
628 if (e == NULL) {
629 break;
630 }
631
632 const UnicodeString* id = (const UnicodeString*)e->key.pointer;
633 if (fallbackKey != NULL) {
634 if (!fallbackKey->isFallbackOf(*id)) {
635 continue;
636 }
637 }
638
639 UnicodeString* idClone = new UnicodeString(*id);
640 if (idClone == NULL || idClone->isBogus()) {
641 delete idClone;
642 status = U_MEMORY_ALLOCATION_ERROR;
643 break;
644 }
645 result.addElement(idClone, status);
646 if (U_FAILURE(status)) {
647 delete idClone;
648 break;
649 }
650 }
651 delete fallbackKey;
652 }
653 }
654 if (U_FAILURE(status)) {
655 result.removeAllElements();
656 }
657 return result;
658 }
659
660 const Hashtable*
661 ICUService::getVisibleIDMap(UErrorCode& status) const {
662 if (U_FAILURE(status)) return NULL;
663
664 // must only be called when lock is already held
665
666 ICUService* ncthis = (ICUService*)this; // cast away semantic const
667 if (idCache == NULL) {
668 ncthis->idCache = new Hashtable(status);
669 if (idCache == NULL) {
670 status = U_MEMORY_ALLOCATION_ERROR;
671 } else if (factories != NULL) {
672 for (int32_t pos = factories->size(); --pos >= 0;) {
673 ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(pos);
674 f->updateVisibleIDs(*idCache, status);
675 }
676 if (U_FAILURE(status)) {
677 delete idCache;
678 ncthis->idCache = NULL;
679 }
680 }
681 }
682
683 return idCache;
684 }
685
686
687 UnicodeString&
688 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const
689 {
690 return getDisplayName(id, result, Locale::getDefault());
691 }
692
693 UnicodeString&
694 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const
695 {
696 {
697 UErrorCode status = U_ZERO_ERROR;
698 Mutex mutex(lock());
699 const Hashtable* map = getVisibleIDMap(status);
700 if (map != NULL) {
701 ICUServiceFactory* f = (ICUServiceFactory*)map->get(id);
702 if (f != NULL) {
703 f->getDisplayName(id, locale, result);
704 return result;
705 }
706
707 // fallback
708 status = U_ZERO_ERROR;
709 ICUServiceKey* fallbackKey = createKey(&id, status);
710 while (fallbackKey != NULL && fallbackKey->fallback()) {
711 UnicodeString us;
712 fallbackKey->currentID(us);
713 f = (ICUServiceFactory*)map->get(us);
714 if (f != NULL) {
715 f->getDisplayName(id, locale, result);
716 delete fallbackKey;
717 return result;
718 }
719 }
720 delete fallbackKey;
721 }
722 }
723 result.setToBogus();
724 return result;
725 }
726
727 UVector&
728 ICUService::getDisplayNames(UVector& result, UErrorCode& status) const
729 {
730 return getDisplayNames(result, Locale::getDefault(), NULL, status);
731 }
732
733
734 UVector&
735 ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const
736 {
737 return getDisplayNames(result, locale, NULL, status);
738 }
739
740 UVector&
741 ICUService::getDisplayNames(UVector& result,
742 const Locale& locale,
743 const UnicodeString* matchID,
744 UErrorCode& status) const
745 {
746 result.removeAllElements();
747 result.setDeleter(userv_deleteStringPair);
748 if (U_SUCCESS(status)) {
749 ICUService* ncthis = (ICUService*)this; // cast away semantic const
750 Mutex mutex(lock());
751
752 if (dnCache != NULL && dnCache->locale != locale) {
753 delete dnCache;
754 ncthis->dnCache = NULL;
755 }
756
757 if (dnCache == NULL) {
758 const Hashtable* m = getVisibleIDMap(status);
759 if (U_FAILURE(status)) {
760 return result;
761 }
762 ncthis->dnCache = new DNCache(locale);
763 if (dnCache == NULL) {
764 status = U_MEMORY_ALLOCATION_ERROR;
765 return result;
766 }
767
768 int32_t pos = UHASH_FIRST;
769 const UHashElement* entry = NULL;
770 while ((entry = m->nextElement(pos)) != NULL) {
771 const UnicodeString* id = (const UnicodeString*)entry->key.pointer;
772 ICUServiceFactory* f = (ICUServiceFactory*)entry->value.pointer;
773 UnicodeString dname;
774 f->getDisplayName(*id, locale, dname);
775 if (dname.isBogus()) {
776 status = U_MEMORY_ALLOCATION_ERROR;
777 } else {
778 dnCache->cache.put(dname, (void*)id, status); // share pointer with visibleIDMap
779 if (U_SUCCESS(status)) {
780 continue;
781 }
782 }
783 delete dnCache;
784 ncthis->dnCache = NULL;
785 return result;
786 }
787 }
788 }
789
790 ICUServiceKey* matchKey = createKey(matchID, status);
791 /* To ensure that all elements in the hashtable are iterated, set pos to -1.
792 * nextElement(pos) will skip the position at pos and begin the iteration
793 * at the next position, which in this case will be 0.
794 */
795 int32_t pos = UHASH_FIRST;
796 const UHashElement *entry = NULL;
797 while ((entry = dnCache->cache.nextElement(pos)) != NULL) {
798 const UnicodeString* id = (const UnicodeString*)entry->value.pointer;
799 if (matchKey != NULL && !matchKey->isFallbackOf(*id)) {
800 continue;
801 }
802 const UnicodeString* dn = (const UnicodeString*)entry->key.pointer;
803 StringPair* sp = StringPair::create(*id, *dn, status);
804 result.addElement(sp, status);
805 if (U_FAILURE(status)) {
806 result.removeAllElements();
807 break;
808 }
809 }
810 delete matchKey;
811
812 return result;
813 }
814
815 URegistryKey
816 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status)
817 {
818 return registerInstance(objToAdopt, id, TRUE, status);
819 }
820
821 URegistryKey
822 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
823 {
824 ICUServiceKey* key = createKey(&id, status);
825 if (key != NULL) {
826 UnicodeString canonicalID;
827 key->canonicalID(canonicalID);
828 delete key;
829
830 ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status);
831 if (f != NULL) {
832 return registerFactory(f, status);
833 }
834 }
835 delete objToAdopt;
836 return NULL;
837 }
838
839 ICUServiceFactory*
840 ICUService::createSimpleFactory(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
841 {
842 if (U_SUCCESS(status)) {
843 if ((objToAdopt != NULL) && (!id.isBogus())) {
844 return new SimpleFactory(objToAdopt, id, visible);
845 }
846 status = U_ILLEGAL_ARGUMENT_ERROR;
847 }
848 return NULL;
849 }
850
851 URegistryKey
852 ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status)
853 {
854 if (U_SUCCESS(status) && factoryToAdopt != NULL) {
855 Mutex mutex(lock());
856
857 if (factories == NULL) {
858 factories = new UVector(deleteUObject, NULL, status);
859 if (U_FAILURE(status)) {
860 delete factories;
861 return NULL;
862 }
863 }
864 factories->insertElementAt(factoryToAdopt, 0, status);
865 if (U_SUCCESS(status)) {
866 clearCaches();
867 } else {
868 delete factoryToAdopt;
869 factoryToAdopt = NULL;
870 }
871 }
872
873 if (factoryToAdopt != NULL) {
874 notifyChanged();
875 }
876
877 return (URegistryKey)factoryToAdopt;
878 }
879
880 UBool
881 ICUService::unregister(URegistryKey rkey, UErrorCode& status)
882 {
883 ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
884 UBool result = FALSE;
885 if (factory != NULL && factories != NULL) {
886 Mutex mutex(lock());
887
888 if (factories->removeElement(factory)) {
889 clearCaches();
890 result = TRUE;
891 } else {
892 status = U_ILLEGAL_ARGUMENT_ERROR;
893 delete factory;
894 }
895 }
896 if (result) {
897 notifyChanged();
898 }
899 return result;
900 }
901
902 void
903 ICUService::reset()
904 {
905 {
906 Mutex mutex(lock());
907 reInitializeFactories();
908 clearCaches();
909 }
910 notifyChanged();
911 }
912
913 void
914 ICUService::reInitializeFactories()
915 {
916 if (factories != NULL) {
917 factories->removeAllElements();
918 }
919 }
920
921 UBool
922 ICUService::isDefault() const
923 {
924 return countFactories() == 0;
925 }
926
927 ICUServiceKey*
928 ICUService::createKey(const UnicodeString* id, UErrorCode& status) const
929 {
930 return (U_FAILURE(status) || id == NULL) ? NULL : new ICUServiceKey(*id);
931 }
932
933 void
934 ICUService::clearCaches()
935 {
936 // callers synchronize before use
937 ++timestamp;
938 delete dnCache;
939 dnCache = NULL;
940 delete idCache;
941 idCache = NULL;
942 delete serviceCache; serviceCache = NULL;
943 }
944
945 void
946 ICUService::clearServiceCache()
947 {
948 // callers synchronize before use
949 delete serviceCache; serviceCache = NULL;
950 }
951
952 UBool
953 ICUService::acceptsListener(const EventListener& l) const
954 {
955 return dynamic_cast<const ServiceListener*>(&l) != NULL;
956 }
957
958 void
959 ICUService::notifyListener(EventListener& l) const
960 {
961 ((ServiceListener&)l).serviceChanged(*this);
962 }
963
964 UnicodeString&
965 ICUService::getName(UnicodeString& result) const
966 {
967 return result.append(name);
968 }
969
970 int32_t
971 ICUService::countFactories() const
972 {
973 return factories == NULL ? 0 : factories->size();
974 }
975
976 int32_t
977 ICUService::getTimestamp() const
978 {
979 return timestamp;
980 }
981
982 U_NAMESPACE_END
983
984 /* UCONFIG_NO_SERVICE */
985 #endif