]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/serv.cpp
ICU-400.37.tar.gz
[apple/icu.git] / icuSources / common / serv.cpp
CommitLineData
46f4442e
A
1/**
2*******************************************************************************
3* Copyright (C) 2001-2008, International Business Machines Corporation. *
4* All Rights Reserved. *
5*******************************************************************************
6*/
b75a7d8f
A
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 21/*
46f4442e
A
22******************************************************************
23*/
b75a7d8f
A
24
25const UChar ICUServiceKey::PREFIX_DELIMITER = 0x002F; /* '/' */
26
27ICUServiceKey::ICUServiceKey(const UnicodeString& id)
46f4442e 28: _id(id) {
b75a7d8f
A
29}
30
31ICUServiceKey::~ICUServiceKey()
32{
33}
34
35const UnicodeString&
36ICUServiceKey::getID() const
37{
46f4442e 38 return _id;
b75a7d8f
A
39}
40
41UnicodeString&
42ICUServiceKey::canonicalID(UnicodeString& result) const
43{
46f4442e 44 return result.append(_id);
b75a7d8f
A
45}
46
47UnicodeString&
48ICUServiceKey::currentID(UnicodeString& result) const
49{
46f4442e 50 return canonicalID(result);
b75a7d8f
A
51}
52
53UnicodeString&
54ICUServiceKey::currentDescriptor(UnicodeString& result) const
55{
46f4442e
A
56 prefix(result);
57 result.append(PREFIX_DELIMITER);
58 return currentID(result);
b75a7d8f
A
59}
60
61UBool
62ICUServiceKey::fallback()
63{
46f4442e 64 return FALSE;
b75a7d8f
A
65}
66
67UBool
68ICUServiceKey::isFallbackOf(const UnicodeString& id) const
69{
46f4442e 70 return id == _id;
b75a7d8f
A
71}
72
73UnicodeString&
74ICUServiceKey::prefix(UnicodeString& result) const
75{
46f4442e 76 return result;
b75a7d8f
A
77}
78
79UnicodeString&
80ICUServiceKey::parsePrefix(UnicodeString& result)
81{
46f4442e
A
82 int32_t n = result.indexOf(PREFIX_DELIMITER);
83 if (n < 0) {
84 n = 0;
85 }
86 result.remove(n);
87 return result;
b75a7d8f
A
88}
89
90UnicodeString&
91ICUServiceKey::parseSuffix(UnicodeString& result)
92{
46f4442e
A
93 int32_t n = result.indexOf(PREFIX_DELIMITER);
94 if (n >= 0) {
95 result.remove(0, n+1);
96 }
97 return result;
b75a7d8f
A
98}
99
100#ifdef SERVICE_DEBUG
101UnicodeString&
102ICUServiceKey::debug(UnicodeString& result) const
103{
46f4442e
A
104 debugClass(result);
105 result.append(" id: ");
106 result.append(_id);
107 return result;
b75a7d8f
A
108}
109
110UnicodeString&
111ICUServiceKey::debugClass(UnicodeString& result) const
112{
46f4442e 113 return result.append("ICUServiceKey");
b75a7d8f
A
114}
115#endif
116
374ca955 117UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUServiceKey)
b75a7d8f
A
118
119/*
46f4442e
A
120******************************************************************
121*/
b75a7d8f
A
122
123SimpleFactory::SimpleFactory(UObject* instanceToAdopt, const UnicodeString& id, UBool visible)
46f4442e 124: _instance(instanceToAdopt), _id(id), _visible(visible)
b75a7d8f
A
125{
126}
127
128SimpleFactory::~SimpleFactory()
129{
46f4442e 130 delete _instance;
b75a7d8f
A
131}
132
133UObject*
134SimpleFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const
135{
46f4442e
A
136 if (U_SUCCESS(status)) {
137 UnicodeString temp;
138 if (_id == key.currentID(temp)) {
139 return service->cloneInstance(_instance);
140 }
b75a7d8f 141 }
46f4442e 142 return NULL;
b75a7d8f
A
143}
144
145void
146SimpleFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const
147{
46f4442e
A
148 if (_visible) {
149 result.put(_id, (void*)this, status); // cast away const
150 } else {
151 result.remove(_id);
152 }
b75a7d8f
A
153}
154
155UnicodeString&
374ca955 156SimpleFactory::getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const
b75a7d8f 157{
46f4442e
A
158 if (_visible && _id == id) {
159 result = _id;
160 } else {
161 result.setToBogus();
162 }
163 return result;
b75a7d8f
A
164}
165
166#ifdef SERVICE_DEBUG
167UnicodeString&
168SimpleFactory::debug(UnicodeString& toAppendTo) const
169{
46f4442e
A
170 debugClass(toAppendTo);
171 toAppendTo.append(" id: ");
172 toAppendTo.append(_id);
173 toAppendTo.append(", visible: ");
174 toAppendTo.append(_visible ? "T" : "F");
175 return toAppendTo;
b75a7d8f
A
176}
177
178UnicodeString&
179SimpleFactory::debugClass(UnicodeString& toAppendTo) const
180{
46f4442e 181 return toAppendTo.append("SimpleFactory");
b75a7d8f
A
182}
183#endif
184
374ca955 185UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleFactory)
b75a7d8f
A
186
187/*
46f4442e
A
188******************************************************************
189*/
b75a7d8f 190
374ca955 191UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceListener)
b75a7d8f
A
192
193/*
46f4442e
A
194******************************************************************
195*/
b75a7d8f 196
46f4442e
A
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.
b75a7d8f
A
199class CacheEntry : public UMemory {
200private:
46f4442e 201 int32_t refcount;
b75a7d8f
A
202
203public:
46f4442e
A
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 }
b75a7d8f
A
251};
252
253// UObjectDeleter for serviceCache
374ca955
A
254U_CDECL_BEGIN
255static void U_CALLCONV
b75a7d8f 256cacheDeleter(void* obj) {
46f4442e 257 U_NAMESPACE_USE ((CacheEntry*)obj)->unref();
b75a7d8f
A
258}
259
260/**
46f4442e
A
261* Deleter for UObjects
262*/
374ca955 263static void U_CALLCONV
b75a7d8f 264deleteUObject(void *obj) {
46f4442e 265 U_NAMESPACE_USE delete (UObject*) obj;
b75a7d8f 266}
374ca955 267U_CDECL_END
b75a7d8f
A
268
269/*
46f4442e
A
270******************************************************************
271*/
b75a7d8f
A
272
273class DNCache : public UMemory {
274public:
46f4442e
A
275 Hashtable cache;
276 const Locale locale;
277
278 DNCache(const Locale& _locale)
279 : cache(), locale(_locale)
280 {
281 // cache.setKeyDeleter(uhash_deleteUnicodeString);
282 }
b75a7d8f
A
283};
284
285
286/*
46f4442e
A
287******************************************************************
288*/
b75a7d8f
A
289
290StringPair*
291StringPair::create(const UnicodeString& displayName,
292 const UnicodeString& id,
293 UErrorCode& status)
294{
46f4442e
A
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;
b75a7d8f 303 }
46f4442e 304 return NULL;
b75a7d8f
A
305}
306
307UBool
308StringPair::isBogus() const {
46f4442e 309 return displayName.isBogus() || id.isBogus();
b75a7d8f
A
310}
311
312StringPair::StringPair(const UnicodeString& _displayName,
313 const UnicodeString& _id)
46f4442e
A
314: displayName(_displayName)
315, id(_id)
b75a7d8f
A
316{
317}
318
46f4442e
A
319U_CDECL_BEGIN
320static void U_CALLCONV
374ca955 321userv_deleteStringPair(void *obj) {
46f4442e 322 U_NAMESPACE_USE delete (StringPair*) obj;
b75a7d8f 323}
46f4442e 324U_CDECL_END
b75a7d8f
A
325
326/*
46f4442e
A
327******************************************************************
328*/
b75a7d8f
A
329
330ICUService::ICUService()
46f4442e
A
331: name()
332, lock(0)
333, timestamp(0)
334, factories(NULL)
335, serviceCache(NULL)
336, idCache(NULL)
337, dnCache(NULL)
b75a7d8f 338{
46f4442e 339 umtx_init(&lock);
b75a7d8f
A
340}
341
342ICUService::ICUService(const UnicodeString& newName)
46f4442e
A
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);
b75a7d8f
A
352}
353
354ICUService::~ICUService()
46f4442e
A
355{
356 {
357 Mutex mutex(&lock);
358 clearCaches();
359 delete factories;
360 factories = NULL;
361 }
362 umtx_destroy(&lock);
b75a7d8f
A
363}
364
365UObject*
366ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const
367{
46f4442e 368 return get(descriptor, NULL, status);
b75a7d8f
A
369}
370
371UObject*
372ICUService::get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const
373{
46f4442e 374 UObject* result = NULL;
b75a7d8f
A
375 ICUServiceKey* key = createKey(&descriptor, status);
376 if (key) {
46f4442e
A
377 result = getKey(*key, actualReturn, status);
378 delete key;
b75a7d8f 379 }
46f4442e 380 return result;
b75a7d8f
A
381}
382
383UObject*
384ICUService::getKey(ICUServiceKey& key, UErrorCode& status) const
385{
46f4442e 386 return getKey(key, NULL, status);
b75a7d8f
A
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{
46f4442e 395 return getKey(key, actualReturn, NULL, status);
b75a7d8f
A
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:
46f4442e
A
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 }
b75a7d8f
A
412
413private:
46f4442e
A
414 UMTX *fMutex;
415 UBool fActive;
b75a7d8f
A
416};
417
418struct UVectorDeleter {
46f4442e
A
419 UVector* _obj;
420 UVectorDeleter() : _obj(NULL) {}
421 ~UVectorDeleter() { delete _obj; }
b75a7d8f
A
422};
423
424// called only by factories, treat as private
425UObject*
426ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUServiceFactory* factory, UErrorCode& status) const
427{
46f4442e 428 if (U_FAILURE(status)) {
b75a7d8f 429 return NULL;
b75a7d8f
A
430 }
431
46f4442e
A
432 if (isDefault()) {
433 return handleDefault(key, actualReturn, status);
434 }
b75a7d8f 435
46f4442e 436 ICUService* ncthis = (ICUService*)this; // cast away semantic const
b75a7d8f 437
46f4442e
A
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);
b75a7d8f 461 }
b75a7d8f 462
46f4442e
A
463 UnicodeString currentDescriptor;
464 UVectorDeleter cacheDescriptorList;
465 UBool putInCache = FALSE;
b75a7d8f 466
46f4442e
A
467 int32_t startIndex = 0;
468 int32_t limit = factories->size();
469 UBool cacheResult = TRUE;
b75a7d8f 470
46f4442e
A
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;
b75a7d8f
A
484 }
485
46f4442e
A
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);
b75a7d8f 537 if (U_FAILURE(status)) {
46f4442e
A
538 return NULL;
539 }
540 } while (key.fallback());
541outerEnd:
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 }
b75a7d8f
A
564 }
565
46f4442e
A
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 }
b75a7d8f 583
46f4442e
A
584 UObject* service = cloneInstance(result->service);
585 if (putInCache && !cacheResult) {
586 delete result;
587 }
588 return service;
b75a7d8f 589 }
b75a7d8f 590 }
b75a7d8f 591
46f4442e 592 return handleDefault(key, actualReturn, status);
b75a7d8f
A
593}
594
595UObject*
374ca955 596ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const
b75a7d8f 597{
46f4442e 598 return NULL;
b75a7d8f 599}
46f4442e 600
b75a7d8f
A
601UVector&
602ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const {
46f4442e 603 return getVisibleIDs(result, NULL, status);
b75a7d8f
A
604}
605
606UVector&
607ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const
608{
46f4442e 609 result.removeAllElements();
b75a7d8f 610
46f4442e
A
611 if (U_FAILURE(status)) {
612 return result;
613 }
b75a7d8f 614
46f4442e
A
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;
b75a7d8f 648 }
b75a7d8f 649 }
46f4442e
A
650 if (U_FAILURE(status)) {
651 result.removeAllElements();
652 }
653 return result;
b75a7d8f
A
654}
655
656const Hashtable*
657ICUService::getVisibleIDMap(UErrorCode& status) const {
46f4442e 658 if (U_FAILURE(status)) return NULL;
b75a7d8f 659
46f4442e 660 // must only be called when lock is already held
b75a7d8f 661
46f4442e 662 ICUService* ncthis = (ICUService*)this; // cast away semantic const
b75a7d8f 663 if (idCache == NULL) {
46f4442e
A
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 }
b75a7d8f 677 }
b75a7d8f 678
46f4442e 679 return idCache;
b75a7d8f
A
680}
681
46f4442e 682
b75a7d8f
A
683UnicodeString&
684ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const
685{
46f4442e 686 return getDisplayName(id, result, Locale::getDefault());
b75a7d8f
A
687}
688
689UnicodeString&
690ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const
691{
46f4442e
A
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;
b75a7d8f
A
722}
723
724UVector&
725ICUService::getDisplayNames(UVector& result, UErrorCode& status) const
726{
46f4442e 727 return getDisplayNames(result, Locale::getDefault(), NULL, status);
b75a7d8f
A
728}
729
730
731UVector&
732ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const
733{
46f4442e 734 return getDisplayNames(result, locale, NULL, status);
b75a7d8f
A
735}
736
737UVector&
738ICUService::getDisplayNames(UVector& result,
739 const Locale& locale,
740 const UnicodeString* matchID,
741 UErrorCode& status) const
742{
46f4442e
A
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);
b75a7d8f 748
46f4442e
A
749 if (dnCache != NULL && dnCache->locale != locale) {
750 delete dnCache;
751 ncthis->dnCache = NULL;
b75a7d8f
A
752 }
753
46f4442e
A
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 }
b75a7d8f 782 }
b75a7d8f 783 }
b75a7d8f 784 }
b75a7d8f 785
46f4442e
A
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 }
b75a7d8f 805 }
46f4442e 806 delete matchKey;
b75a7d8f 807
46f4442e 808 return result;
b75a7d8f
A
809}
810
811URegistryKey
812ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status)
813{
46f4442e 814 return registerInstance(objToAdopt, id, TRUE, status);
b75a7d8f
A
815}
816
817URegistryKey
818ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
819{
46f4442e
A
820 ICUServiceKey* key = createKey(&id, status);
821 if (key != NULL) {
822 UnicodeString canonicalID;
823 key->canonicalID(canonicalID);
824 delete key;
b75a7d8f 825
46f4442e
A
826 ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status);
827 if (f != NULL) {
828 return registerFactory(f, status);
829 }
b75a7d8f 830 }
46f4442e
A
831 delete objToAdopt;
832 return NULL;
b75a7d8f
A
833}
834
835ICUServiceFactory*
836ICUService::createSimpleFactory(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
837{
46f4442e
A
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;
b75a7d8f 843 }
46f4442e 844 return NULL;
b75a7d8f
A
845}
846
847URegistryKey
848ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status)
849{
46f4442e
A
850 if (U_SUCCESS(status) && factoryToAdopt != NULL) {
851 Mutex mutex(&lock);
b75a7d8f 852
46f4442e
A
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 }
b75a7d8f 867 }
b75a7d8f 868
46f4442e
A
869 if (factoryToAdopt != NULL) {
870 notifyChanged();
871 }
b75a7d8f 872
46f4442e 873 return (URegistryKey)factoryToAdopt;
b75a7d8f
A
874}
875
876UBool
877ICUService::unregister(URegistryKey rkey, UErrorCode& status)
878{
46f4442e
A
879 ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
880 UBool result = FALSE;
881 if (factory != NULL && factories != NULL) {
882 Mutex mutex(&lock);
b75a7d8f 883
46f4442e
A
884 if (factories->removeElement(factory)) {
885 clearCaches();
886 result = TRUE;
887 } else {
888 status = U_ILLEGAL_ARGUMENT_ERROR;
889 delete factory;
890 }
b75a7d8f 891 }
46f4442e
A
892 if (result) {
893 notifyChanged();
894 }
895 return result;
b75a7d8f
A
896}
897
898void
899ICUService::reset()
900{
46f4442e
A
901 {
902 Mutex mutex(&lock);
903 reInitializeFactories();
904 clearCaches();
905 }
906 notifyChanged();
b75a7d8f
A
907}
908
909void
910ICUService::reInitializeFactories()
911{
46f4442e
A
912 if (factories != NULL) {
913 factories->removeAllElements();
914 }
b75a7d8f
A
915}
916
917UBool
918ICUService::isDefault() const
919{
46f4442e 920 return countFactories() == 0;
b75a7d8f
A
921}
922
923ICUServiceKey*
924ICUService::createKey(const UnicodeString* id, UErrorCode& status) const
925{
46f4442e 926 return (U_FAILURE(status) || id == NULL) ? NULL : new ICUServiceKey(*id);
b75a7d8f
A
927}
928
929void
930ICUService::clearCaches()
931{
46f4442e
A
932 // callers synchronize before use
933 ++timestamp;
934 delete dnCache;
935 dnCache = NULL;
936 delete idCache;
937 idCache = NULL;
938 delete serviceCache; serviceCache = NULL;
b75a7d8f
A
939}
940
941void
942ICUService::clearServiceCache()
943{
46f4442e
A
944 // callers synchronize before use
945 delete serviceCache; serviceCache = NULL;
b75a7d8f
A
946}
947
948UBool
949ICUService::acceptsListener(const EventListener& l) const
950{
46f4442e 951 return l.getDynamicClassID() == ServiceListener::getStaticClassID();
b75a7d8f
A
952}
953
954void
955ICUService::notifyListener(EventListener& l) const
956{
46f4442e 957 ((ServiceListener&)l).serviceChanged(*this);
b75a7d8f
A
958}
959
960UnicodeString&
961ICUService::getName(UnicodeString& result) const
962{
46f4442e 963 return result.append(name);
b75a7d8f
A
964}
965
966int32_t
967ICUService::countFactories() const
968{
46f4442e 969 return factories == NULL ? 0 : factories->size();
b75a7d8f
A
970}
971
972int32_t
973ICUService::getTimestamp() const
974{
46f4442e 975 return timestamp;
b75a7d8f
A
976}
977
978U_NAMESPACE_END
979
980/* UCONFIG_NO_SERVICE */
981#endif