]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/serv.cpp
ICU-400.42.tar.gz
[apple/icu.git] / icuSources / common / serv.cpp
1 /**
2 *******************************************************************************
3 * Copyright (C) 2001-2008, 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(" id: ");
106 result.append(_id);
107 return result;
108 }
109
110 UnicodeString&
111 ICUServiceKey::debugClass(UnicodeString& result) const
112 {
113 return result.append("ICUServiceKey");
114 }
115 #endif
116
117 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUServiceKey)
118
119 /*
120 ******************************************************************
121 */
122
123 SimpleFactory::SimpleFactory(UObject* instanceToAdopt, const UnicodeString& id, UBool visible)
124 : _instance(instanceToAdopt), _id(id), _visible(visible)
125 {
126 }
127
128 SimpleFactory::~SimpleFactory()
129 {
130 delete _instance;
131 }
132
133 UObject*
134 SimpleFactory::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
145 void
146 SimpleFactory::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
155 UnicodeString&
156 SimpleFactory::getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const
157 {
158 if (_visible && _id == id) {
159 result = _id;
160 } else {
161 result.setToBogus();
162 }
163 return result;
164 }
165
166 #ifdef SERVICE_DEBUG
167 UnicodeString&
168 SimpleFactory::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
178 UnicodeString&
179 SimpleFactory::debugClass(UnicodeString& toAppendTo) const
180 {
181 return toAppendTo.append("SimpleFactory");
182 }
183 #endif
184
185 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleFactory)
186
187 /*
188 ******************************************************************
189 */
190
191 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceListener)
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.
199 class CacheEntry : public UMemory {
200 private:
201 int32_t refcount;
202
203 public:
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
254 U_CDECL_BEGIN
255 static void U_CALLCONV
256 cacheDeleter(void* obj) {
257 U_NAMESPACE_USE ((CacheEntry*)obj)->unref();
258 }
259
260 /**
261 * Deleter for UObjects
262 */
263 static void U_CALLCONV
264 deleteUObject(void *obj) {
265 U_NAMESPACE_USE delete (UObject*) obj;
266 }
267 U_CDECL_END
268
269 /*
270 ******************************************************************
271 */
272
273 class DNCache : public UMemory {
274 public:
275 Hashtable cache;
276 const Locale locale;
277
278 DNCache(const Locale& _locale)
279 : cache(), locale(_locale)
280 {
281 // cache.setKeyDeleter(uhash_deleteUnicodeString);
282 }
283 };
284
285
286 /*
287 ******************************************************************
288 */
289
290 StringPair*
291 StringPair::create(const UnicodeString& displayName,
292 const UnicodeString& id,
293 UErrorCode& status)
294 {
295 if (U_SUCCESS(status)) {
296 StringPair* sp = new StringPair(displayName, id);
297 if (sp == NULL || sp->isBogus()) {
298 status = U_MEMORY_ALLOCATION_ERROR;
299 delete sp;
300 return NULL;
301 }
302 return sp;
303 }
304 return NULL;
305 }
306
307 UBool
308 StringPair::isBogus() const {
309 return displayName.isBogus() || id.isBogus();
310 }
311
312 StringPair::StringPair(const UnicodeString& _displayName,
313 const UnicodeString& _id)
314 : displayName(_displayName)
315 , id(_id)
316 {
317 }
318
319 U_CDECL_BEGIN
320 static void U_CALLCONV
321 userv_deleteStringPair(void *obj) {
322 U_NAMESPACE_USE delete (StringPair*) obj;
323 }
324 U_CDECL_END
325
326 /*
327 ******************************************************************
328 */
329
330 ICUService::ICUService()
331 : name()
332 , lock(0)
333 , timestamp(0)
334 , factories(NULL)
335 , serviceCache(NULL)
336 , idCache(NULL)
337 , dnCache(NULL)
338 {
339 umtx_init(&lock);
340 }
341
342 ICUService::ICUService(const UnicodeString& newName)
343 : name(newName)
344 , lock(0)
345 , timestamp(0)
346 , factories(NULL)
347 , serviceCache(NULL)
348 , idCache(NULL)
349 , dnCache(NULL)
350 {
351 umtx_init(&lock);
352 }
353
354 ICUService::~ICUService()
355 {
356 {
357 Mutex mutex(&lock);
358 clearCaches();
359 delete factories;
360 factories = NULL;
361 }
362 umtx_destroy(&lock);
363 }
364
365 UObject*
366 ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const
367 {
368 return get(descriptor, NULL, status);
369 }
370
371 UObject*
372 ICUService::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
383 UObject*
384 ICUService::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
392 UObject*
393 ICUService::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.
401 class XMutex : public UMemory {
402 public:
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
413 private:
414 UMTX *fMutex;
415 UBool fActive;
416 };
417
418 struct UVectorDeleter {
419 UVector* _obj;
420 UVectorDeleter() : _obj(NULL) {}
421 ~UVectorDeleter() { delete _obj; }
422 };
423
424 // called only by factories, treat as private
425 UObject*
426 ICUService::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.
445
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 mutex(&ncthis->lock, factory != NULL);
450
451 if (serviceCache == NULL) {
452 ncthis->serviceCache = new Hashtable(status);
453 if (ncthis->serviceCache == NULL) {
454 return NULL;
455 }
456 if (U_FAILURE(status)) {
457 delete serviceCache;
458 return NULL;
459 }
460 serviceCache->setValueDeleter(cacheDeleter);
461 }
462
463 UnicodeString currentDescriptor;
464 UVectorDeleter cacheDescriptorList;
465 UBool putInCache = FALSE;
466
467 int32_t startIndex = 0;
468 int32_t limit = factories->size();
469 UBool cacheResult = TRUE;
470
471 if (factory != NULL) {
472 for (int32_t i = 0; i < limit; ++i) {
473 if (factory == (const ICUServiceFactory*)factories->elementAt(i)) {
474 startIndex = i + 1;
475 break;
476 }
477 }
478 if (startIndex == 0) {
479 // throw new InternalError("Factory " + factory + "not registered with service: " + this);
480 status = U_ILLEGAL_ARGUMENT_ERROR;
481 return NULL;
482 }
483 cacheResult = FALSE;
484 }
485
486 do {
487 currentDescriptor.remove();
488 key.currentDescriptor(currentDescriptor);
489 result = (CacheEntry*)serviceCache->get(currentDescriptor);
490 if (result != NULL) {
491 break;
492 }
493
494 // first test of cache failed, so we'll have to update
495 // the cache if we eventually succeed-- that is, if we're
496 // going to update the cache at all.
497 putInCache = TRUE;
498
499 int32_t index = startIndex;
500 while (index < limit) {
501 ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(index++);
502 UObject* service = f->create(key, this, status);
503 if (U_FAILURE(status)) {
504 delete service;
505 return NULL;
506 }
507 if (service != NULL) {
508 result = new CacheEntry(currentDescriptor, service);
509 if (result == NULL) {
510 delete service;
511 status = U_MEMORY_ALLOCATION_ERROR;
512 return NULL;
513 }
514
515 goto outerEnd;
516 }
517 }
518
519 // prepare to load the cache with all additional ids that
520 // will resolve to result, assuming we'll succeed. We
521 // don't want to keep querying on an id that's going to
522 // fallback to the one that succeeded, we want to hit the
523 // cache the first time next goaround.
524 if (cacheDescriptorList._obj == NULL) {
525 cacheDescriptorList._obj = new UVector(uhash_deleteUnicodeString, NULL, 5, status);
526 if (U_FAILURE(status)) {
527 return NULL;
528 }
529 }
530 UnicodeString* idToCache = new UnicodeString(currentDescriptor);
531 if (idToCache == NULL || idToCache->isBogus()) {
532 status = U_MEMORY_ALLOCATION_ERROR;
533 return NULL;
534 }
535
536 cacheDescriptorList._obj->addElement(idToCache, status);
537 if (U_FAILURE(status)) {
538 return NULL;
539 }
540 } while (key.fallback());
541 outerEnd:
542
543 if (result != NULL) {
544 if (putInCache && cacheResult) {
545 serviceCache->put(result->actualDescriptor, result, status);
546 if (U_FAILURE(status)) {
547 delete result;
548 return NULL;
549 }
550
551 if (cacheDescriptorList._obj != NULL) {
552 for (int32_t i = cacheDescriptorList._obj->size(); --i >= 0;) {
553 UnicodeString* desc = (UnicodeString*)cacheDescriptorList._obj->elementAt(i);
554 serviceCache->put(*desc, result, status);
555 if (U_FAILURE(status)) {
556 delete result;
557 return NULL;
558 }
559
560 result->ref();
561 cacheDescriptorList._obj->removeElementAt(i);
562 }
563 }
564 }
565
566 if (actualReturn != NULL) {
567 // strip null prefix
568 if (result->actualDescriptor.indexOf((UChar)0x2f) == 0) { // U+002f=slash (/)
569 actualReturn->remove();
570 actualReturn->append(result->actualDescriptor,
571 1,
572 result->actualDescriptor.length() - 1);
573 } else {
574 *actualReturn = result->actualDescriptor;
575 }
576
577 if (actualReturn->isBogus()) {
578 status = U_MEMORY_ALLOCATION_ERROR;
579 delete result;
580 return NULL;
581 }
582 }
583
584 UObject* service = cloneInstance(result->service);
585 if (putInCache && !cacheResult) {
586 delete result;
587 }
588 return service;
589 }
590 }
591
592 return handleDefault(key, actualReturn, status);
593 }
594
595 UObject*
596 ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const
597 {
598 return NULL;
599 }
600
601 UVector&
602 ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const {
603 return getVisibleIDs(result, NULL, status);
604 }
605
606 UVector&
607 ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const
608 {
609 result.removeAllElements();
610
611 if (U_FAILURE(status)) {
612 return result;
613 }
614
615 ICUService * ncthis = (ICUService*)this; // cast away semantic const
616 {
617 Mutex mutex(&ncthis->lock);
618 const Hashtable* map = getVisibleIDMap(status);
619 if (map != NULL) {
620 ICUServiceKey* fallbackKey = createKey(matchID, status);
621
622 for (int32_t pos = -1;;) {
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 ICUService* ncthis = (ICUService*)this; // cast away semantic const
694 UErrorCode status = U_ZERO_ERROR;
695 Mutex mutex(&ncthis->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 UErrorCode status = U_ZERO_ERROR;
706 ICUServiceKey* fallbackKey = createKey(&id, status);
707 while (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(&ncthis->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 (m != NULL) {
757 ncthis->dnCache = new DNCache(locale);
758 if (dnCache == NULL) {
759 status = U_MEMORY_ALLOCATION_ERROR;
760 return result;
761 }
762
763 int32_t pos = -1;
764 const UHashElement* entry = NULL;
765 while ((entry = m->nextElement(pos)) != NULL) {
766 const UnicodeString* id = (const UnicodeString*)entry->key.pointer;
767 ICUServiceFactory* f = (ICUServiceFactory*)entry->value.pointer;
768 UnicodeString dname;
769 f->getDisplayName(*id, locale, dname);
770 if (dname.isBogus()) {
771 status = U_MEMORY_ALLOCATION_ERROR;
772 } else {
773 dnCache->cache.put(dname, (void*)id, status); // share pointer with visibleIDMap
774 if (U_SUCCESS(status)) {
775 continue;
776 }
777 }
778 delete dnCache;
779 ncthis->dnCache = NULL;
780 return result;
781 }
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 = -1;
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 l.getDynamicClassID() == ServiceListener::getStaticClassID();
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