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