1 /**
2 *******************************************************************************
3 * Copyright (C) 2001-2011, 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
ICUServiceKey(const UnicodeString & id)27 ICUServiceKey::ICUServiceKey(const UnicodeString& id)
28 : _id(id) {
29 }
30
~ICUServiceKey()31 ICUServiceKey::~ICUServiceKey()
32 {
33 }
34
35 const UnicodeString&
getID() const36 ICUServiceKey::getID() const
37 {
38 return _id;
39 }
40
41 UnicodeString&
canonicalID(UnicodeString & result) const42 ICUServiceKey::canonicalID(UnicodeString& result) const
43 {
44 return result.append(_id);
45 }
46
47 UnicodeString&
currentID(UnicodeString & result) const48 ICUServiceKey::currentID(UnicodeString& result) const
49 {
50 return canonicalID(result);
51 }
52
53 UnicodeString&
currentDescriptor(UnicodeString & result) const54 ICUServiceKey::currentDescriptor(UnicodeString& result) const
55 {
56 prefix(result);
57 result.append(PREFIX_DELIMITER);
58 return currentID(result);
59 }
60
61 UBool
fallback()62 ICUServiceKey::fallback()
63 {
64 return FALSE;
65 }
66
67 UBool
isFallbackOf(const UnicodeString & id) const68 ICUServiceKey::isFallbackOf(const UnicodeString& id) const
69 {
70 return id == _id;
71 }
72
73 UnicodeString&
prefix(UnicodeString & result) const74 ICUServiceKey::prefix(UnicodeString& result) const
75 {
76 return result;
77 }
78
79 UnicodeString&
parsePrefix(UnicodeString & result)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&
parseSuffix(UnicodeString & result)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&
debug(UnicodeString & result) const102 ICUServiceKey::debug(UnicodeString& result) const
103 {
104 debugClass(result);
105 result.append(" id: ");
106 result.append(_id);
107 return result;
108 }
109
110 UnicodeString&
debugClass(UnicodeString & result) const111 ICUServiceKey::debugClass(UnicodeString& result) const
112 {
113 return result.append("ICUServiceKey");
114 }
115 #endif
116
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUServiceKey)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
~SimpleFactory()128 SimpleFactory::~SimpleFactory()
129 {
130 delete _instance;
131 }
132
133 UObject*
create(const ICUServiceKey & key,const ICUService * service,UErrorCode & status) const134 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
updateVisibleIDs(Hashtable & result,UErrorCode & status) const146 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&
getDisplayName(const UnicodeString & id,const Locale &,UnicodeString & result) const156 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&
debug(UnicodeString & toAppendTo) const168 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&
debugClass(UnicodeString & toAppendTo) const179 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 */
~CacheEntry()210 ~CacheEntry() {
211 delete service;
212 }
213
CacheEntry(const UnicodeString & _actualDescriptor,UObject * _service)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 */
ref()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 */
unref()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 */
isShared() const248 UBool isShared() const {
249 return refcount > 1;
250 }
251 };
252
253 // UObjectDeleter for serviceCache
254 U_CDECL_BEGIN
255 static void U_CALLCONV
cacheDeleter(void * obj)256 cacheDeleter(void* obj) {
257 U_NAMESPACE_USE ((CacheEntry*)obj)->unref();
258 }
259
260 /**
261 * Deleter for UObjects
262 */
263 static void U_CALLCONV
deleteUObject(void * obj)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
DNCache(const Locale & _locale)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*
create(const UnicodeString & displayName,const UnicodeString & id,UErrorCode & status)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
isBogus() const308 StringPair::isBogus() const {
309 return displayName.isBogus() || id.isBogus();
310 }
311
StringPair(const UnicodeString & _displayName,const UnicodeString & _id)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
userv_deleteStringPair(void * obj)321 userv_deleteStringPair(void *obj) {
322 U_NAMESPACE_USE delete (StringPair*) obj;
323 }
324 U_CDECL_END
325
326 /*
327 ******************************************************************
328 */
329
330 static UMTX lock;
331
ICUService()332 ICUService::ICUService()
333 : name()
334 , timestamp(0)
335 , factories(NULL)
336 , serviceCache(NULL)
337 , idCache(NULL)
338 , dnCache(NULL)
339 {
340 }
341
ICUService(const UnicodeString & newName)342 ICUService::ICUService(const UnicodeString& newName)
343 : name(newName)
344 , timestamp(0)
345 , factories(NULL)
346 , serviceCache(NULL)
347 , idCache(NULL)
348 , dnCache(NULL)
349 {
350 }
351
~ICUService()352 ICUService::~ICUService()
353 {
354 {
355 Mutex mutex(&lock);
356 clearCaches();
357 delete factories;
358 factories = NULL;
359 }
360 }
361
362 UObject*
get(const UnicodeString & descriptor,UErrorCode & status) const363 ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const
364 {
365 return get(descriptor, NULL, status);
366 }
367
368 UObject*
get(const UnicodeString & descriptor,UnicodeString * actualReturn,UErrorCode & status) const369 ICUService::get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const
370 {
371 UObject* result = NULL;
372 ICUServiceKey* key = createKey(&descriptor, status);
373 if (key) {
374 result = getKey(*key, actualReturn, status);
375 delete key;
376 }
377 return result;
378 }
379
380 UObject*
getKey(ICUServiceKey & key,UErrorCode & status) const381 ICUService::getKey(ICUServiceKey& key, UErrorCode& status) const
382 {
383 return getKey(key, NULL, status);
384 }
385
386 // this is a vector that subclasses of ICUService can override to further customize the result object
387 // before returning it. All other public get functions should call this one.
388
389 UObject*
getKey(ICUServiceKey & key,UnicodeString * actualReturn,UErrorCode & status) const390 ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const
391 {
392 return getKey(key, actualReturn, NULL, status);
393 }
394
395 // make it possible to call reentrantly on systems that don't have reentrant mutexes.
396 // we can use this simple approach since we know the situation where we're calling
397 // reentrantly even without knowing the thread.
398 class XMutex : public UMemory {
399 public:
XMutex(UMTX * mutex,UBool reentering)400 inline XMutex(UMTX *mutex, UBool reentering)
401 : fMutex(mutex)
402 , fActive(!reentering)
403 {
404 if (fActive) umtx_lock(fMutex);
405 }
~XMutex()406 inline ~XMutex() {
407 if (fActive) umtx_unlock(fMutex);
408 }
409
410 private:
411 UMTX *fMutex;
412 UBool fActive;
413 };
414
415 struct UVectorDeleter {
416 UVector* _obj;
UVectorDeleterUVectorDeleter417 UVectorDeleter() : _obj(NULL) {}
~UVectorDeleterUVectorDeleter418 ~UVectorDeleter() { delete _obj; }
419 };
420
421 // called only by factories, treat as private
422 UObject*
getKey(ICUServiceKey & key,UnicodeString * actualReturn,const ICUServiceFactory * factory,UErrorCode & status) const423 ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUServiceFactory* factory, UErrorCode& status) const
424 {
425 if (U_FAILURE(status)) {
426 return NULL;
427 }
428
429 if (isDefault()) {
430 return handleDefault(key, actualReturn, status);
431 }
432
433 ICUService* ncthis = (ICUService*)this; // cast away semantic const
434
435 CacheEntry* result = NULL;
436 {
437 // The factory list can't be modified until we're done,
438 // otherwise we might update the cache with an invalid result.
439 // The cache has to stay in synch with the factory list.
440 // ICU doesn't have monitors so we can't use rw locks, so
441 // we single-thread everything using this service, for now.
442
443 // if factory is not null, we're calling from within the mutex,
444 // and since some unix machines don't have reentrant mutexes we
445 // need to make sure not to try to lock it again.
446 XMutex mutex(&lock, factory != NULL);
447
448 if (serviceCache == NULL) {
449 ncthis->serviceCache = new Hashtable(status);
450 if (ncthis->serviceCache == NULL) {
451 return NULL;
452 }
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
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
565 if (result->actualDescriptor.indexOf((UChar)0x2f) == 0) { // U+002f=slash (/)
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;
576 delete result;
577 return NULL;
578 }
579 }
580
581 UObject* service = cloneInstance(result->service);
582 if (putInCache && !cacheResult) {
583 delete result;
584 }
585 return service;
586 }
587 }
588
589 return handleDefault(key, actualReturn, status);
590 }
591
592 UObject*
handleDefault(const ICUServiceKey &,UnicodeString *,UErrorCode &) const593 ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const
594 {
595 return NULL;
596 }
597
598 UVector&
getVisibleIDs(UVector & result,UErrorCode & status) const599 ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const {
600 return getVisibleIDs(result, NULL, status);
601 }
602
603 UVector&
getVisibleIDs(UVector & result,const UnicodeString * matchID,UErrorCode & status) const604 ICUService::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 {
613 Mutex mutex(&lock);
614 const Hashtable* map = getVisibleIDMap(status);
615 if (map != NULL) {
616 ICUServiceKey* fallbackKey = createKey(matchID, status);
617
618 for (int32_t pos = -1;;) {
619 const UHashElement* e = map->nextElement(pos);
620 if (e == NULL) {
621 break;
622 }
623
624 const UnicodeString* id = (const UnicodeString*)e->key.pointer;
625 if (fallbackKey != NULL) {
626 if (!fallbackKey->isFallbackOf(*id)) {
627 continue;
628 }
629 }
630
631 UnicodeString* idClone = new UnicodeString(*id);
632 if (idClone == NULL || idClone->isBogus()) {
633 delete idClone;
634 status = U_MEMORY_ALLOCATION_ERROR;
635 break;
636 }
637 result.addElement(idClone, status);
638 if (U_FAILURE(status)) {
639 delete idClone;
640 break;
641 }
642 }
643 delete fallbackKey;
644 }
645 }
646 if (U_FAILURE(status)) {
647 result.removeAllElements();
648 }
649 return result;
650 }
651
652 const Hashtable*
getVisibleIDMap(UErrorCode & status) const653 ICUService::getVisibleIDMap(UErrorCode& status) const {
654 if (U_FAILURE(status)) return NULL;
655
656 // must only be called when lock is already held
657
658 ICUService* ncthis = (ICUService*)this; // cast away semantic const
659 if (idCache == NULL) {
660 ncthis->idCache = new Hashtable(status);
661 if (idCache == NULL) {
662 status = U_MEMORY_ALLOCATION_ERROR;
663 } else if (factories != NULL) {
664 for (int32_t pos = factories->size(); --pos >= 0;) {
665 ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(pos);
666 f->updateVisibleIDs(*idCache, status);
667 }
668 if (U_FAILURE(status)) {
669 delete idCache;
670 ncthis->idCache = NULL;
671 }
672 }
673 }
674
675 return idCache;
676 }
677
678
679 UnicodeString&
getDisplayName(const UnicodeString & id,UnicodeString & result) const680 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const
681 {
682 return getDisplayName(id, result, Locale::getDefault());
683 }
684
685 UnicodeString&
getDisplayName(const UnicodeString & id,UnicodeString & result,const Locale & locale) const686 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const
687 {
688 {
689 UErrorCode status = U_ZERO_ERROR;
690 Mutex mutex(&lock);
691 const Hashtable* map = getVisibleIDMap(status);
692 if (map != NULL) {
693 ICUServiceFactory* f = (ICUServiceFactory*)map->get(id);
694 if (f != NULL) {
695 f->getDisplayName(id, locale, result);
696 return result;
697 }
698
699 // fallback
700 UErrorCode status = U_ZERO_ERROR;
701 ICUServiceKey* fallbackKey = createKey(&id, status);
702 while (fallbackKey->fallback()) {
703 UnicodeString us;
704 fallbackKey->currentID(us);
705 f = (ICUServiceFactory*)map->get(us);
706 if (f != NULL) {
707 f->getDisplayName(id, locale, result);
708 delete fallbackKey;
709 return result;
710 }
711 }
712 delete fallbackKey;
713 }
714 }
715 result.setToBogus();
716 return result;
717 }
718
719 UVector&
getDisplayNames(UVector & result,UErrorCode & status) const720 ICUService::getDisplayNames(UVector& result, UErrorCode& status) const
721 {
722 return getDisplayNames(result, Locale::getDefault(), NULL, status);
723 }
724
725
726 UVector&
getDisplayNames(UVector & result,const Locale & locale,UErrorCode & status) const727 ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const
728 {
729 return getDisplayNames(result, locale, NULL, status);
730 }
731
732 UVector&
getDisplayNames(UVector & result,const Locale & locale,const UnicodeString * matchID,UErrorCode & status) const733 ICUService::getDisplayNames(UVector& result,
734 const Locale& locale,
735 const UnicodeString* matchID,
736 UErrorCode& status) const
737 {
738 result.removeAllElements();
739 result.setDeleter(userv_deleteStringPair);
740 if (U_SUCCESS(status)) {
741 ICUService* ncthis = (ICUService*)this; // cast away semantic const
742 Mutex mutex(&lock);
743
744 if (dnCache != NULL && dnCache->locale != locale) {
745 delete dnCache;
746 ncthis->dnCache = NULL;
747 }
748
749 if (dnCache == NULL) {
750 const Hashtable* m = getVisibleIDMap(status);
751 if (m != NULL) {
752 ncthis->dnCache = new DNCache(locale);
753 if (dnCache == NULL) {
754 status = U_MEMORY_ALLOCATION_ERROR;
755 return result;
756 }
757
758 int32_t pos = -1;
759 const UHashElement* entry = NULL;
760 while ((entry = m->nextElement(pos)) != NULL) {
761 const UnicodeString* id = (const UnicodeString*)entry->key.pointer;
762 ICUServiceFactory* f = (ICUServiceFactory*)entry->value.pointer;
763 UnicodeString dname;
764 f->getDisplayName(*id, locale, dname);
765 if (dname.isBogus()) {
766 status = U_MEMORY_ALLOCATION_ERROR;
767 } else {
768 dnCache->cache.put(dname, (void*)id, status); // share pointer with visibleIDMap
769 if (U_SUCCESS(status)) {
770 continue;
771 }
772 }
773 delete dnCache;
774 ncthis->dnCache = NULL;
775 return result;
776 }
777 }
778 }
779 }
780
781 ICUServiceKey* matchKey = createKey(matchID, status);
782 /* To ensure that all elements in the hashtable are iterated, set pos to -1.
783 * nextElement(pos) will skip the position at pos and begin the iteration
784 * at the next position, which in this case will be 0.
785 */
786 int32_t pos = -1;
787 const UHashElement *entry = NULL;
788 while ((entry = dnCache->cache.nextElement(pos)) != NULL) {
789 const UnicodeString* id = (const UnicodeString*)entry->value.pointer;
790 if (matchKey != NULL && !matchKey->isFallbackOf(*id)) {
791 continue;
792 }
793 const UnicodeString* dn = (const UnicodeString*)entry->key.pointer;
794 StringPair* sp = StringPair::create(*id, *dn, status);
795 result.addElement(sp, status);
796 if (U_FAILURE(status)) {
797 result.removeAllElements();
798 break;
799 }
800 }
801 delete matchKey;
802
803 return result;
804 }
805
806 URegistryKey
registerInstance(UObject * objToAdopt,const UnicodeString & id,UErrorCode & status)807 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status)
808 {
809 return registerInstance(objToAdopt, id, TRUE, status);
810 }
811
812 URegistryKey
registerInstance(UObject * objToAdopt,const UnicodeString & id,UBool visible,UErrorCode & status)813 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
814 {
815 ICUServiceKey* key = createKey(&id, status);
816 if (key != NULL) {
817 UnicodeString canonicalID;
818 key->canonicalID(canonicalID);
819 delete key;
820
821 ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status);
822 if (f != NULL) {
823 return registerFactory(f, status);
824 }
825 }
826 delete objToAdopt;
827 return NULL;
828 }
829
830 ICUServiceFactory*
createSimpleFactory(UObject * objToAdopt,const UnicodeString & id,UBool visible,UErrorCode & status)831 ICUService::createSimpleFactory(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
832 {
833 if (U_SUCCESS(status)) {
834 if ((objToAdopt != NULL) && (!id.isBogus())) {
835 return new SimpleFactory(objToAdopt, id, visible);
836 }
837 status = U_ILLEGAL_ARGUMENT_ERROR;
838 }
839 return NULL;
840 }
841
842 URegistryKey
registerFactory(ICUServiceFactory * factoryToAdopt,UErrorCode & status)843 ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status)
844 {
845 if (U_SUCCESS(status) && factoryToAdopt != NULL) {
846 Mutex mutex(&lock);
847
848 if (factories == NULL) {
849 factories = new UVector(deleteUObject, NULL, status);
850 if (U_FAILURE(status)) {
851 delete factories;
852 return NULL;
853 }
854 }
855 factories->insertElementAt(factoryToAdopt, 0, status);
856 if (U_SUCCESS(status)) {
857 clearCaches();
858 } else {
859 delete factoryToAdopt;
860 factoryToAdopt = NULL;
861 }
862 }
863
864 if (factoryToAdopt != NULL) {
865 notifyChanged();
866 }
867
868 return (URegistryKey)factoryToAdopt;
869 }
870
871 UBool
unregister(URegistryKey rkey,UErrorCode & status)872 ICUService::unregister(URegistryKey rkey, UErrorCode& status)
873 {
874 ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
875 UBool result = FALSE;
876 if (factory != NULL && factories != NULL) {
877 Mutex mutex(&lock);
878
879 if (factories->removeElement(factory)) {
880 clearCaches();
881 result = TRUE;
882 } else {
883 status = U_ILLEGAL_ARGUMENT_ERROR;
884 delete factory;
885 }
886 }
887 if (result) {
888 notifyChanged();
889 }
890 return result;
891 }
892
893 void
reset()894 ICUService::reset()
895 {
896 {
897 Mutex mutex(&lock);
898 reInitializeFactories();
899 clearCaches();
900 }
901 notifyChanged();
902 }
903
904 void
reInitializeFactories()905 ICUService::reInitializeFactories()
906 {
907 if (factories != NULL) {
908 factories->removeAllElements();
909 }
910 }
911
912 UBool
isDefault() const913 ICUService::isDefault() const
914 {
915 return countFactories() == 0;
916 }
917
918 ICUServiceKey*
createKey(const UnicodeString * id,UErrorCode & status) const919 ICUService::createKey(const UnicodeString* id, UErrorCode& status) const
920 {
921 return (U_FAILURE(status) || id == NULL) ? NULL : new ICUServiceKey(*id);
922 }
923
924 void
clearCaches()925 ICUService::clearCaches()
926 {
927 // callers synchronize before use
928 ++timestamp;
929 delete dnCache;
930 dnCache = NULL;
931 delete idCache;
932 idCache = NULL;
933 delete serviceCache; serviceCache = NULL;
934 }
935
936 void
clearServiceCache()937 ICUService::clearServiceCache()
938 {
939 // callers synchronize before use
940 delete serviceCache; serviceCache = NULL;
941 }
942
943 UBool
acceptsListener(const EventListener & l) const944 ICUService::acceptsListener(const EventListener& l) const
945 {
946 return dynamic_cast<const ServiceListener*>(&l) != NULL;
947 }
948
949 void
notifyListener(EventListener & l) const950 ICUService::notifyListener(EventListener& l) const
951 {
952 ((ServiceListener&)l).serviceChanged(*this);
953 }
954
955 UnicodeString&
getName(UnicodeString & result) const956 ICUService::getName(UnicodeString& result) const
957 {
958 return result.append(name);
959 }
960
961 int32_t
countFactories() const962 ICUService::countFactories() const
963 {
964 return factories == NULL ? 0 : factories->size();
965 }
966
967 int32_t
getTimestamp() const968 ICUService::getTimestamp() const
969 {
970 return timestamp;
971 }
972
973 U_NAMESPACE_END
974
975 /* UCONFIG_NO_SERVICE */
976 #endif
977