]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/serv.cpp
ICU-531.48.tar.gz
[apple/icu.git] / icuSources / common / serv.cpp
CommitLineData
46f4442e
A
1/**
2*******************************************************************************
51004dcb 3* Copyright (C) 2001-2012, International Business Machines Corporation.
729e4ab9 4* All Rights Reserved.
46f4442e
A
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 122
4388f060
A
123ICUServiceFactory::~ICUServiceFactory() {}
124
b75a7d8f 125SimpleFactory::SimpleFactory(UObject* instanceToAdopt, const UnicodeString& id, UBool visible)
46f4442e 126: _instance(instanceToAdopt), _id(id), _visible(visible)
b75a7d8f
A
127{
128}
129
130SimpleFactory::~SimpleFactory()
131{
46f4442e 132 delete _instance;
b75a7d8f
A
133}
134
135UObject*
136SimpleFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const
137{
46f4442e
A
138 if (U_SUCCESS(status)) {
139 UnicodeString temp;
140 if (_id == key.currentID(temp)) {
141 return service->cloneInstance(_instance);
142 }
b75a7d8f 143 }
46f4442e 144 return NULL;
b75a7d8f
A
145}
146
147void
148SimpleFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const
149{
46f4442e
A
150 if (_visible) {
151 result.put(_id, (void*)this, status); // cast away const
152 } else {
153 result.remove(_id);
154 }
b75a7d8f
A
155}
156
157UnicodeString&
374ca955 158SimpleFactory::getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const
b75a7d8f 159{
46f4442e
A
160 if (_visible && _id == id) {
161 result = _id;
162 } else {
163 result.setToBogus();
164 }
165 return result;
b75a7d8f
A
166}
167
168#ifdef SERVICE_DEBUG
169UnicodeString&
170SimpleFactory::debug(UnicodeString& toAppendTo) const
171{
46f4442e
A
172 debugClass(toAppendTo);
173 toAppendTo.append(" id: ");
174 toAppendTo.append(_id);
175 toAppendTo.append(", visible: ");
176 toAppendTo.append(_visible ? "T" : "F");
177 return toAppendTo;
b75a7d8f
A
178}
179
180UnicodeString&
181SimpleFactory::debugClass(UnicodeString& toAppendTo) const
182{
46f4442e 183 return toAppendTo.append("SimpleFactory");
b75a7d8f
A
184}
185#endif
186
374ca955 187UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleFactory)
b75a7d8f
A
188
189/*
46f4442e
A
190******************************************************************
191*/
b75a7d8f 192
4388f060
A
193ServiceListener::~ServiceListener() {}
194
374ca955 195UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceListener)
b75a7d8f
A
196
197/*
46f4442e
A
198******************************************************************
199*/
b75a7d8f 200
46f4442e
A
201// Record the actual id for this service in the cache, so we can return it
202// even if we succeed later with a different id.
b75a7d8f
A
203class CacheEntry : public UMemory {
204private:
46f4442e 205 int32_t refcount;
b75a7d8f
A
206
207public:
46f4442e
A
208 UnicodeString actualDescriptor;
209 UObject* service;
210
211 /**
212 * Releases a reference to the shared resource.
213 */
214 ~CacheEntry() {
215 delete service;
216 }
217
218 CacheEntry(const UnicodeString& _actualDescriptor, UObject* _service)
219 : refcount(1), actualDescriptor(_actualDescriptor), service(_service) {
220 }
221
222 /**
223 * Instantiation creates an initial reference, so don't call this
224 * unless you're creating a new pointer to this. Management of
225 * that pointer will have to know how to deal with refcounts.
226 * Return true if the resource has not already been released.
227 */
228 CacheEntry* ref() {
229 ++refcount;
230 return this;
231 }
232
233 /**
234 * Destructions removes a reference, so don't call this unless
235 * you're removing pointer to this somewhere. Management of that
236 * pointer will have to know how to deal with refcounts. Once
237 * the refcount drops to zero, the resource is released. Return
238 * false if the resouce has been released.
239 */
240 CacheEntry* unref() {
241 if ((--refcount) == 0) {
242 delete this;
243 return NULL;
244 }
245 return this;
246 }
247
248 /**
249 * Return TRUE if there is at least one reference to this and the
250 * resource has not been released.
251 */
252 UBool isShared() const {
253 return refcount > 1;
254 }
b75a7d8f
A
255};
256
257// UObjectDeleter for serviceCache
374ca955
A
258U_CDECL_BEGIN
259static void U_CALLCONV
b75a7d8f 260cacheDeleter(void* obj) {
46f4442e 261 U_NAMESPACE_USE ((CacheEntry*)obj)->unref();
b75a7d8f
A
262}
263
264/**
46f4442e
A
265* Deleter for UObjects
266*/
374ca955 267static void U_CALLCONV
b75a7d8f 268deleteUObject(void *obj) {
46f4442e 269 U_NAMESPACE_USE delete (UObject*) obj;
b75a7d8f 270}
374ca955 271U_CDECL_END
b75a7d8f
A
272
273/*
46f4442e
A
274******************************************************************
275*/
b75a7d8f
A
276
277class DNCache : public UMemory {
278public:
46f4442e
A
279 Hashtable cache;
280 const Locale locale;
281
282 DNCache(const Locale& _locale)
283 : cache(), locale(_locale)
284 {
4388f060 285 // cache.setKeyDeleter(uprv_deleteUObject);
46f4442e 286 }
b75a7d8f
A
287};
288
289
290/*
46f4442e
A
291******************************************************************
292*/
b75a7d8f
A
293
294StringPair*
295StringPair::create(const UnicodeString& displayName,
296 const UnicodeString& id,
297 UErrorCode& status)
298{
46f4442e
A
299 if (U_SUCCESS(status)) {
300 StringPair* sp = new StringPair(displayName, id);
301 if (sp == NULL || sp->isBogus()) {
302 status = U_MEMORY_ALLOCATION_ERROR;
303 delete sp;
304 return NULL;
305 }
306 return sp;
b75a7d8f 307 }
46f4442e 308 return NULL;
b75a7d8f
A
309}
310
311UBool
312StringPair::isBogus() const {
46f4442e 313 return displayName.isBogus() || id.isBogus();
b75a7d8f
A
314}
315
316StringPair::StringPair(const UnicodeString& _displayName,
317 const UnicodeString& _id)
46f4442e
A
318: displayName(_displayName)
319, id(_id)
b75a7d8f
A
320{
321}
322
46f4442e
A
323U_CDECL_BEGIN
324static void U_CALLCONV
374ca955 325userv_deleteStringPair(void *obj) {
46f4442e 326 U_NAMESPACE_USE delete (StringPair*) obj;
b75a7d8f 327}
46f4442e 328U_CDECL_END
b75a7d8f
A
329
330/*
46f4442e
A
331******************************************************************
332*/
b75a7d8f 333
51004dcb 334static UMutex lock = U_MUTEX_INITIALIZER;
4388f060 335
b75a7d8f 336ICUService::ICUService()
46f4442e 337: name()
46f4442e
A
338, timestamp(0)
339, factories(NULL)
340, serviceCache(NULL)
341, idCache(NULL)
342, dnCache(NULL)
b75a7d8f 343{
b75a7d8f
A
344}
345
346ICUService::ICUService(const UnicodeString& newName)
46f4442e 347: name(newName)
46f4442e
A
348, timestamp(0)
349, factories(NULL)
350, serviceCache(NULL)
351, idCache(NULL)
352, dnCache(NULL)
353{
b75a7d8f
A
354}
355
356ICUService::~ICUService()
46f4442e
A
357{
358 {
359 Mutex mutex(&lock);
360 clearCaches();
361 delete factories;
362 factories = NULL;
363 }
b75a7d8f
A
364}
365
366UObject*
367ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const
368{
46f4442e 369 return get(descriptor, NULL, status);
b75a7d8f
A
370}
371
372UObject*
373ICUService::get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const
374{
46f4442e 375 UObject* result = NULL;
b75a7d8f
A
376 ICUServiceKey* key = createKey(&descriptor, status);
377 if (key) {
46f4442e
A
378 result = getKey(*key, actualReturn, status);
379 delete key;
b75a7d8f 380 }
46f4442e 381 return result;
b75a7d8f
A
382}
383
384UObject*
385ICUService::getKey(ICUServiceKey& key, UErrorCode& status) const
386{
46f4442e 387 return getKey(key, NULL, status);
b75a7d8f
A
388}
389
390// this is a vector that subclasses of ICUService can override to further customize the result object
391// before returning it. All other public get functions should call this one.
392
393UObject*
394ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const
395{
46f4442e 396 return getKey(key, actualReturn, NULL, status);
b75a7d8f
A
397}
398
399// make it possible to call reentrantly on systems that don't have reentrant mutexes.
400// we can use this simple approach since we know the situation where we're calling
401// reentrantly even without knowing the thread.
402class XMutex : public UMemory {
403public:
51004dcb 404 inline XMutex(UMutex *mutex, UBool reentering)
46f4442e
A
405 : fMutex(mutex)
406 , fActive(!reentering)
407 {
408 if (fActive) umtx_lock(fMutex);
409 }
410 inline ~XMutex() {
411 if (fActive) umtx_unlock(fMutex);
412 }
b75a7d8f
A
413
414private:
51004dcb 415 UMutex *fMutex;
46f4442e 416 UBool fActive;
b75a7d8f
A
417};
418
419struct UVectorDeleter {
46f4442e
A
420 UVector* _obj;
421 UVectorDeleter() : _obj(NULL) {}
422 ~UVectorDeleter() { delete _obj; }
b75a7d8f
A
423};
424
425// called only by factories, treat as private
426UObject*
427ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUServiceFactory* factory, UErrorCode& status) const
428{
46f4442e 429 if (U_FAILURE(status)) {
b75a7d8f 430 return NULL;
b75a7d8f
A
431 }
432
46f4442e
A
433 if (isDefault()) {
434 return handleDefault(key, actualReturn, status);
435 }
b75a7d8f 436
46f4442e 437 ICUService* ncthis = (ICUService*)this; // cast away semantic const
b75a7d8f 438
46f4442e
A
439 CacheEntry* result = NULL;
440 {
441 // The factory list can't be modified until we're done,
442 // otherwise we might update the cache with an invalid result.
443 // The cache has to stay in synch with the factory list.
444 // ICU doesn't have monitors so we can't use rw locks, so
445 // we single-thread everything using this service, for now.
446
447 // if factory is not null, we're calling from within the mutex,
448 // and since some unix machines don't have reentrant mutexes we
449 // need to make sure not to try to lock it again.
4388f060 450 XMutex mutex(&lock, factory != NULL);
46f4442e
A
451
452 if (serviceCache == NULL) {
453 ncthis->serviceCache = new Hashtable(status);
454 if (ncthis->serviceCache == NULL) {
455 return NULL;
456 }
457 if (U_FAILURE(status)) {
458 delete serviceCache;
459 return NULL;
460 }
461 serviceCache->setValueDeleter(cacheDeleter);
b75a7d8f 462 }
b75a7d8f 463
46f4442e
A
464 UnicodeString currentDescriptor;
465 UVectorDeleter cacheDescriptorList;
466 UBool putInCache = FALSE;
b75a7d8f 467
46f4442e
A
468 int32_t startIndex = 0;
469 int32_t limit = factories->size();
470 UBool cacheResult = TRUE;
b75a7d8f 471
46f4442e
A
472 if (factory != NULL) {
473 for (int32_t i = 0; i < limit; ++i) {
474 if (factory == (const ICUServiceFactory*)factories->elementAt(i)) {
475 startIndex = i + 1;
476 break;
477 }
478 }
479 if (startIndex == 0) {
480 // throw new InternalError("Factory " + factory + "not registered with service: " + this);
481 status = U_ILLEGAL_ARGUMENT_ERROR;
482 return NULL;
483 }
484 cacheResult = FALSE;
b75a7d8f
A
485 }
486
46f4442e
A
487 do {
488 currentDescriptor.remove();
489 key.currentDescriptor(currentDescriptor);
490 result = (CacheEntry*)serviceCache->get(currentDescriptor);
491 if (result != NULL) {
492 break;
493 }
494
495 // first test of cache failed, so we'll have to update
496 // the cache if we eventually succeed-- that is, if we're
497 // going to update the cache at all.
498 putInCache = TRUE;
499
500 int32_t index = startIndex;
501 while (index < limit) {
502 ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(index++);
503 UObject* service = f->create(key, this, status);
504 if (U_FAILURE(status)) {
505 delete service;
506 return NULL;
507 }
508 if (service != NULL) {
509 result = new CacheEntry(currentDescriptor, service);
510 if (result == NULL) {
511 delete service;
512 status = U_MEMORY_ALLOCATION_ERROR;
513 return NULL;
514 }
515
516 goto outerEnd;
517 }
518 }
519
520 // prepare to load the cache with all additional ids that
521 // will resolve to result, assuming we'll succeed. We
522 // don't want to keep querying on an id that's going to
523 // fallback to the one that succeeded, we want to hit the
524 // cache the first time next goaround.
525 if (cacheDescriptorList._obj == NULL) {
4388f060 526 cacheDescriptorList._obj = new UVector(uprv_deleteUObject, NULL, 5, status);
46f4442e
A
527 if (U_FAILURE(status)) {
528 return NULL;
529 }
530 }
531 UnicodeString* idToCache = new UnicodeString(currentDescriptor);
532 if (idToCache == NULL || idToCache->isBogus()) {
533 status = U_MEMORY_ALLOCATION_ERROR;
534 return NULL;
535 }
536
537 cacheDescriptorList._obj->addElement(idToCache, status);
b75a7d8f 538 if (U_FAILURE(status)) {
46f4442e
A
539 return NULL;
540 }
541 } while (key.fallback());
542outerEnd:
543
544 if (result != NULL) {
545 if (putInCache && cacheResult) {
546 serviceCache->put(result->actualDescriptor, result, status);
547 if (U_FAILURE(status)) {
548 delete result;
549 return NULL;
550 }
551
552 if (cacheDescriptorList._obj != NULL) {
553 for (int32_t i = cacheDescriptorList._obj->size(); --i >= 0;) {
554 UnicodeString* desc = (UnicodeString*)cacheDescriptorList._obj->elementAt(i);
555 serviceCache->put(*desc, result, status);
556 if (U_FAILURE(status)) {
557 delete result;
558 return NULL;
559 }
560
561 result->ref();
562 cacheDescriptorList._obj->removeElementAt(i);
563 }
564 }
b75a7d8f
A
565 }
566
46f4442e
A
567 if (actualReturn != NULL) {
568 // strip null prefix
569 if (result->actualDescriptor.indexOf((UChar)0x2f) == 0) { // U+002f=slash (/)
570 actualReturn->remove();
571 actualReturn->append(result->actualDescriptor,
572 1,
573 result->actualDescriptor.length() - 1);
574 } else {
575 *actualReturn = result->actualDescriptor;
576 }
577
578 if (actualReturn->isBogus()) {
579 status = U_MEMORY_ALLOCATION_ERROR;
580 delete result;
581 return NULL;
582 }
583 }
b75a7d8f 584
46f4442e
A
585 UObject* service = cloneInstance(result->service);
586 if (putInCache && !cacheResult) {
587 delete result;
588 }
589 return service;
b75a7d8f 590 }
b75a7d8f 591 }
b75a7d8f 592
46f4442e 593 return handleDefault(key, actualReturn, status);
b75a7d8f
A
594}
595
596UObject*
374ca955 597ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const
b75a7d8f 598{
46f4442e 599 return NULL;
b75a7d8f 600}
46f4442e 601
b75a7d8f
A
602UVector&
603ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const {
46f4442e 604 return getVisibleIDs(result, NULL, status);
b75a7d8f
A
605}
606
607UVector&
608ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const
609{
46f4442e 610 result.removeAllElements();
b75a7d8f 611
46f4442e
A
612 if (U_FAILURE(status)) {
613 return result;
614 }
b75a7d8f 615
46f4442e 616 {
4388f060 617 Mutex mutex(&lock);
46f4442e
A
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 692 {
46f4442e 693 UErrorCode status = U_ZERO_ERROR;
4388f060 694 Mutex mutex(&lock);
46f4442e
A
695 const Hashtable* map = getVisibleIDMap(status);
696 if (map != NULL) {
697 ICUServiceFactory* f = (ICUServiceFactory*)map->get(id);
698 if (f != NULL) {
699 f->getDisplayName(id, locale, result);
700 return result;
701 }
702
703 // fallback
704 UErrorCode status = U_ZERO_ERROR;
705 ICUServiceKey* fallbackKey = createKey(&id, status);
706 while (fallbackKey->fallback()) {
707 UnicodeString us;
708 fallbackKey->currentID(us);
709 f = (ICUServiceFactory*)map->get(us);
710 if (f != NULL) {
711 f->getDisplayName(id, locale, result);
712 delete fallbackKey;
713 return result;
714 }
715 }
716 delete fallbackKey;
717 }
718 }
719 result.setToBogus();
720 return result;
b75a7d8f
A
721}
722
723UVector&
724ICUService::getDisplayNames(UVector& result, UErrorCode& status) const
725{
46f4442e 726 return getDisplayNames(result, Locale::getDefault(), NULL, status);
b75a7d8f
A
727}
728
729
730UVector&
731ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const
732{
46f4442e 733 return getDisplayNames(result, locale, NULL, status);
b75a7d8f
A
734}
735
736UVector&
737ICUService::getDisplayNames(UVector& result,
738 const Locale& locale,
739 const UnicodeString* matchID,
740 UErrorCode& status) const
741{
46f4442e
A
742 result.removeAllElements();
743 result.setDeleter(userv_deleteStringPair);
744 if (U_SUCCESS(status)) {
745 ICUService* ncthis = (ICUService*)this; // cast away semantic const
4388f060 746 Mutex mutex(&lock);
b75a7d8f 747
46f4442e
A
748 if (dnCache != NULL && dnCache->locale != locale) {
749 delete dnCache;
750 ncthis->dnCache = NULL;
b75a7d8f
A
751 }
752
46f4442e
A
753 if (dnCache == NULL) {
754 const Hashtable* m = getVisibleIDMap(status);
4388f060
A
755 if (U_FAILURE(status)) {
756 return result;
757 }
758 ncthis->dnCache = new DNCache(locale);
759 if (dnCache == NULL) {
760 status = U_MEMORY_ALLOCATION_ERROR;
761 return result;
762 }
46f4442e 763
4388f060
A
764 int32_t pos = -1;
765 const UHashElement* entry = NULL;
766 while ((entry = m->nextElement(pos)) != NULL) {
767 const UnicodeString* id = (const UnicodeString*)entry->key.pointer;
768 ICUServiceFactory* f = (ICUServiceFactory*)entry->value.pointer;
769 UnicodeString dname;
770 f->getDisplayName(*id, locale, dname);
771 if (dname.isBogus()) {
772 status = U_MEMORY_ALLOCATION_ERROR;
773 } else {
774 dnCache->cache.put(dname, (void*)id, status); // share pointer with visibleIDMap
775 if (U_SUCCESS(status)) {
776 continue;
46f4442e 777 }
46f4442e 778 }
4388f060
A
779 delete dnCache;
780 ncthis->dnCache = NULL;
781 return result;
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{
729e4ab9 951 return dynamic_cast<const ServiceListener*>(&l) != NULL;
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