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