Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / icu / source / common / serv.cpp
1 /**
2 *******************************************************************************
3 * Copyright (C) 2001-2012, International Business Machines Corporation.
4 * All Rights Reserved.
5 *******************************************************************************
6 */
7
8 #include "unicode/utypes.h"
9
10 #if !UCONFIG_NO_SERVICE
11
12 #include "serv.h"
13 #include "umutex.h"
14
15 #undef SERVICE_REFCOUNT
16
17 // in case we use the refcount stuff
18
19 U_NAMESPACE_BEGIN
20
21 /*
22 ******************************************************************
23 */
24
25 const UChar ICUServiceKey::PREFIX_DELIMITER = 0x002F;   /* '/' */
26
27 ICUServiceKey::ICUServiceKey(const UnicodeString& id) 
28 : _id(id) {
29 }
30
31 ICUServiceKey::~ICUServiceKey() 
32 {
33 }
34
35 const UnicodeString& 
36 ICUServiceKey::getID() const 
37 {
38     return _id;
39 }
40
41 UnicodeString& 
42 ICUServiceKey::canonicalID(UnicodeString& result) const 
43 {
44     return result.append(_id);
45 }
46
47 UnicodeString& 
48 ICUServiceKey::currentID(UnicodeString& result) const 
49 {
50     return canonicalID(result);
51 }
52
53 UnicodeString& 
54 ICUServiceKey::currentDescriptor(UnicodeString& result) const 
55 {
56     prefix(result);
57     result.append(PREFIX_DELIMITER);
58     return currentID(result);
59 }
60
61 UBool 
62 ICUServiceKey::fallback() 
63 {
64     return FALSE;
65 }
66
67 UBool 
68 ICUServiceKey::isFallbackOf(const UnicodeString& id) const 
69 {
70     return id == _id;
71 }
72
73 UnicodeString& 
74 ICUServiceKey::prefix(UnicodeString& result) const 
75 {
76     return result;
77 }
78
79 UnicodeString& 
80 ICUServiceKey::parsePrefix(UnicodeString& result) 
81 {
82     int32_t n = result.indexOf(PREFIX_DELIMITER);
83     if (n < 0) {
84         n = 0;
85     }
86     result.remove(n);
87     return result;
88 }
89
90 UnicodeString& 
91 ICUServiceKey::parseSuffix(UnicodeString& result) 
92 {
93     int32_t n = result.indexOf(PREFIX_DELIMITER);
94     if (n >= 0) {
95         result.remove(0, n+1);
96     }
97     return result;
98 }
99
100 #ifdef SERVICE_DEBUG
101 UnicodeString& 
102 ICUServiceKey::debug(UnicodeString& result) const 
103 {
104     debugClass(result);
105     result.append(" id: ");
106     result.append(_id);
107     return result;
108 }
109
110 UnicodeString& 
111 ICUServiceKey::debugClass(UnicodeString& result) const 
112 {
113     return result.append("ICUServiceKey");
114 }
115 #endif
116
117 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUServiceKey)
118
119 /*
120 ******************************************************************
121 */
122
123 ICUServiceFactory::~ICUServiceFactory() {}
124
125 SimpleFactory::SimpleFactory(UObject* instanceToAdopt, const UnicodeString& id, UBool visible) 
126 : _instance(instanceToAdopt), _id(id), _visible(visible)
127 {
128 }
129
130 SimpleFactory::~SimpleFactory() 
131 {
132     delete _instance;
133 }
134
135 UObject* 
136 SimpleFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const 
137 {
138     if (U_SUCCESS(status)) {
139         UnicodeString temp;
140         if (_id == key.currentID(temp)) {
141             return service->cloneInstance(_instance); 
142         }
143     }
144     return NULL;
145 }
146
147 void 
148 SimpleFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const 
149 {
150     if (_visible) {
151         result.put(_id, (void*)this, status); // cast away const
152     } else {
153         result.remove(_id);
154     }
155 }
156
157 UnicodeString& 
158 SimpleFactory::getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const 
159 {
160     if (_visible && _id == id) {
161         result = _id;
162     } else {
163         result.setToBogus();
164     }
165     return result;
166 }
167
168 #ifdef SERVICE_DEBUG
169 UnicodeString& 
170 SimpleFactory::debug(UnicodeString& toAppendTo) const 
171 {
172     debugClass(toAppendTo);
173     toAppendTo.append(" id: ");
174     toAppendTo.append(_id);
175     toAppendTo.append(", visible: ");
176     toAppendTo.append(_visible ? "T" : "F");
177     return toAppendTo;
178 }
179
180 UnicodeString& 
181 SimpleFactory::debugClass(UnicodeString& toAppendTo) const 
182 {
183     return toAppendTo.append("SimpleFactory");
184 }
185 #endif
186
187 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleFactory)
188
189 /*
190 ******************************************************************
191 */
192
193 ServiceListener::~ServiceListener() {}
194
195 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceListener)
196
197 /*
198 ******************************************************************
199 */
200
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.
203 class CacheEntry : public UMemory {
204 private:
205     int32_t refcount;
206
207 public:
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     }
255 };
256
257 // UObjectDeleter for serviceCache
258 U_CDECL_BEGIN
259 static void U_CALLCONV
260 cacheDeleter(void* obj) {
261     U_NAMESPACE_USE ((CacheEntry*)obj)->unref();
262 }
263
264 /**
265 * Deleter for UObjects
266 */
267 static void U_CALLCONV
268 deleteUObject(void *obj) {
269     U_NAMESPACE_USE delete (UObject*) obj;
270 }
271 U_CDECL_END
272
273 /*
274 ******************************************************************
275 */
276
277 class DNCache : public UMemory {
278 public:
279     Hashtable cache;
280     const Locale locale;
281
282     DNCache(const Locale& _locale) 
283         : cache(), locale(_locale) 
284     {
285         // cache.setKeyDeleter(uprv_deleteUObject);
286     }
287 };
288
289
290 /*
291 ******************************************************************
292 */
293
294 StringPair* 
295 StringPair::create(const UnicodeString& displayName, 
296                    const UnicodeString& id,
297                    UErrorCode& status)
298 {
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;
307     }
308     return NULL;
309 }
310
311 UBool 
312 StringPair::isBogus() const {
313     return displayName.isBogus() || id.isBogus();
314 }
315
316 StringPair::StringPair(const UnicodeString& _displayName, 
317                        const UnicodeString& _id)
318 : displayName(_displayName)
319 , id(_id)
320 {
321 }
322
323 U_CDECL_BEGIN
324 static void U_CALLCONV
325 userv_deleteStringPair(void *obj) {
326     U_NAMESPACE_USE delete (StringPair*) obj;
327 }
328 U_CDECL_END
329
330 /*
331 ******************************************************************
332 */
333
334 static UMutex lock = U_MUTEX_INITIALIZER;
335
336 ICUService::ICUService()
337 : name()
338 , timestamp(0)
339 , factories(NULL)
340 , serviceCache(NULL)
341 , idCache(NULL)
342 , dnCache(NULL)
343 {
344 }
345
346 ICUService::ICUService(const UnicodeString& newName) 
347 : name(newName)
348 , timestamp(0)
349 , factories(NULL)
350 , serviceCache(NULL)
351 , idCache(NULL)
352 , dnCache(NULL)
353 {
354 }
355
356 ICUService::~ICUService()
357 {
358     {
359         Mutex mutex(&lock);
360         clearCaches();
361         delete factories;
362         factories = NULL;
363     }
364 }
365
366 UObject* 
367 ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const 
368 {
369     return get(descriptor, NULL, status);
370 }
371
372 UObject* 
373 ICUService::get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const 
374 {
375     UObject* result = NULL;
376     ICUServiceKey* key = createKey(&descriptor, status);
377     if (key) {
378         result = getKey(*key, actualReturn, status);
379         delete key;
380     }
381     return result;
382 }
383
384 UObject* 
385 ICUService::getKey(ICUServiceKey& key, UErrorCode& status) const 
386 {
387     return getKey(key, NULL, status);
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
393 UObject* 
394 ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const 
395 {
396     return getKey(key, actualReturn, NULL, status);
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.
402 class XMutex : public UMemory {
403 public:
404     inline XMutex(UMutex *mutex, UBool reentering) 
405         : fMutex(mutex)
406         , fActive(!reentering) 
407     {
408         if (fActive) umtx_lock(fMutex);
409     }
410     inline ~XMutex() {
411         if (fActive) umtx_unlock(fMutex);
412     }
413
414 private:
415     UMutex  *fMutex;
416     UBool fActive;
417 };
418
419 struct UVectorDeleter {
420     UVector* _obj;
421     UVectorDeleter() : _obj(NULL) {}
422     ~UVectorDeleter() { delete _obj; }
423 };
424
425 // called only by factories, treat as private
426 UObject* 
427 ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUServiceFactory* factory, UErrorCode& status) const 
428 {
429     if (U_FAILURE(status)) {
430         return NULL;
431     }
432
433     if (isDefault()) {
434         return handleDefault(key, actualReturn, status);
435     }
436
437     ICUService* ncthis = (ICUService*)this; // cast away semantic const
438
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.
450         XMutex mutex(&lock, factory != NULL);
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);
462         }
463
464         UnicodeString currentDescriptor;
465         UVectorDeleter cacheDescriptorList;
466         UBool putInCache = FALSE;
467
468         int32_t startIndex = 0;
469         int32_t limit = factories->size();
470         UBool cacheResult = TRUE;
471
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;
485         }
486
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) {
526                 cacheDescriptorList._obj = new UVector(uprv_deleteUObject, NULL, 5, status);
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);
538             if (U_FAILURE(status)) {
539                 return NULL;
540             }
541         } while (key.fallback());
542 outerEnd:
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                 }
565             }
566
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             }
584
585             UObject* service = cloneInstance(result->service);
586             if (putInCache && !cacheResult) {
587                 delete result;
588             }
589             return service;
590         }
591     }
592
593     return handleDefault(key, actualReturn, status);
594 }
595
596 UObject* 
597 ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const 
598 {
599     return NULL;
600 }
601
602 UVector& 
603 ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const {
604     return getVisibleIDs(result, NULL, status);
605 }
606
607 UVector& 
608 ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const 
609 {
610     result.removeAllElements();
611
612     if (U_FAILURE(status)) {
613         return result;
614     }
615
616     {
617         Mutex mutex(&lock);
618         const Hashtable* map = getVisibleIDMap(status);
619         if (map != NULL) {
620             ICUServiceKey* fallbackKey = createKey(matchID, status);
621
622             for (int32_t pos = -1;;) {
623                 const UHashElement* e = map->nextElement(pos);
624                 if (e == NULL) {
625                     break;
626                 }
627
628                 const UnicodeString* id = (const UnicodeString*)e->key.pointer;
629                 if (fallbackKey != NULL) {
630                     if (!fallbackKey->isFallbackOf(*id)) {
631                         continue;
632                     }
633                 }
634
635                 UnicodeString* idClone = new UnicodeString(*id);
636                 if (idClone == NULL || idClone->isBogus()) {
637                     delete idClone;
638                     status = U_MEMORY_ALLOCATION_ERROR;
639                     break;
640                 }
641                 result.addElement(idClone, status);
642                 if (U_FAILURE(status)) {
643                     delete idClone;
644                     break;
645                 }
646             }
647             delete fallbackKey;
648         }
649     }
650     if (U_FAILURE(status)) {
651         result.removeAllElements();
652     }
653     return result;
654 }
655
656 const Hashtable* 
657 ICUService::getVisibleIDMap(UErrorCode& status) const {
658     if (U_FAILURE(status)) return NULL;
659
660     // must only be called when lock is already held
661
662     ICUService* ncthis = (ICUService*)this; // cast away semantic const
663     if (idCache == NULL) {
664         ncthis->idCache = new Hashtable(status);
665         if (idCache == NULL) {
666             status = U_MEMORY_ALLOCATION_ERROR;
667         } else if (factories != NULL) {
668             for (int32_t pos = factories->size(); --pos >= 0;) {
669                 ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(pos);
670                 f->updateVisibleIDs(*idCache, status);
671             }
672             if (U_FAILURE(status)) {
673                 delete idCache;
674                 ncthis->idCache = NULL;
675             }
676         }
677     }
678
679     return idCache;
680 }
681
682
683 UnicodeString& 
684 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const 
685 {
686     return getDisplayName(id, result, Locale::getDefault());
687 }
688
689 UnicodeString& 
690 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const 
691 {
692     {
693         UErrorCode status = U_ZERO_ERROR;
694         Mutex mutex(&lock);
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;
721 }
722
723 UVector& 
724 ICUService::getDisplayNames(UVector& result, UErrorCode& status) const 
725 {
726     return getDisplayNames(result, Locale::getDefault(), NULL, status);
727 }
728
729
730 UVector& 
731 ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const 
732 {
733     return getDisplayNames(result, locale, NULL, status);
734 }
735
736 UVector& 
737 ICUService::getDisplayNames(UVector& result, 
738                             const Locale& locale, 
739                             const UnicodeString* matchID, 
740                             UErrorCode& status) const 
741 {
742     result.removeAllElements();
743     result.setDeleter(userv_deleteStringPair);
744     if (U_SUCCESS(status)) {
745         ICUService* ncthis = (ICUService*)this; // cast away semantic const
746         Mutex mutex(&lock);
747
748         if (dnCache != NULL && dnCache->locale != locale) {
749             delete dnCache;
750             ncthis->dnCache = NULL;
751         }
752
753         if (dnCache == NULL) {
754             const Hashtable* m = getVisibleIDMap(status);
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             }
763
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;
777                     }
778                 }
779                 delete dnCache;
780                 ncthis->dnCache = NULL;
781                 return result;
782             }
783         }
784     }
785
786     ICUServiceKey* matchKey = createKey(matchID, status);
787     /* To ensure that all elements in the hashtable are iterated, set pos to -1.
788      * nextElement(pos) will skip the position at pos and begin the iteration
789      * at the next position, which in this case will be 0.
790      */
791     int32_t pos = -1; 
792     const UHashElement *entry = NULL;
793     while ((entry = dnCache->cache.nextElement(pos)) != NULL) {
794         const UnicodeString* id = (const UnicodeString*)entry->value.pointer;
795         if (matchKey != NULL && !matchKey->isFallbackOf(*id)) {
796             continue;
797         }
798         const UnicodeString* dn = (const UnicodeString*)entry->key.pointer;
799         StringPair* sp = StringPair::create(*id, *dn, status);
800         result.addElement(sp, status);
801         if (U_FAILURE(status)) {
802             result.removeAllElements();
803             break;
804         }
805     }
806     delete matchKey;
807
808     return result;
809 }
810
811 URegistryKey
812 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status) 
813 {
814     return registerInstance(objToAdopt, id, TRUE, status);
815 }
816
817 URegistryKey
818 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status) 
819 {
820     ICUServiceKey* key = createKey(&id, status);
821     if (key != NULL) {
822         UnicodeString canonicalID;
823         key->canonicalID(canonicalID);
824         delete key;
825
826         ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status);
827         if (f != NULL) {
828             return registerFactory(f, status);
829         }
830     }
831     delete objToAdopt;
832     return NULL;
833 }
834
835 ICUServiceFactory* 
836 ICUService::createSimpleFactory(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
837 {
838     if (U_SUCCESS(status)) {
839         if ((objToAdopt != NULL) && (!id.isBogus())) {
840             return new SimpleFactory(objToAdopt, id, visible);
841         }
842         status = U_ILLEGAL_ARGUMENT_ERROR;
843     }
844     return NULL;
845 }
846
847 URegistryKey
848 ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status) 
849 {
850     if (U_SUCCESS(status) && factoryToAdopt != NULL) {
851         Mutex mutex(&lock);
852
853         if (factories == NULL) {
854             factories = new UVector(deleteUObject, NULL, status);
855             if (U_FAILURE(status)) {
856                 delete factories;
857                 return NULL;
858             }
859         }
860         factories->insertElementAt(factoryToAdopt, 0, status);
861         if (U_SUCCESS(status)) {
862             clearCaches();
863         } else {
864             delete factoryToAdopt;
865             factoryToAdopt = NULL;
866         }
867     }
868
869     if (factoryToAdopt != NULL) {
870         notifyChanged();
871     }
872
873     return (URegistryKey)factoryToAdopt;
874 }
875
876 UBool 
877 ICUService::unregister(URegistryKey rkey, UErrorCode& status) 
878 {
879     ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
880     UBool result = FALSE;
881     if (factory != NULL && factories != NULL) {
882         Mutex mutex(&lock);
883
884         if (factories->removeElement(factory)) {
885             clearCaches();
886             result = TRUE;
887         } else {
888             status = U_ILLEGAL_ARGUMENT_ERROR;
889             delete factory;
890         }
891     }
892     if (result) {
893         notifyChanged();
894     }
895     return result;
896 }
897
898 void 
899 ICUService::reset() 
900 {
901     {
902         Mutex mutex(&lock);
903         reInitializeFactories();
904         clearCaches();
905     }
906     notifyChanged();
907 }
908
909 void 
910 ICUService::reInitializeFactories() 
911 {
912     if (factories != NULL) {
913         factories->removeAllElements();
914     }
915 }
916
917 UBool 
918 ICUService::isDefault() const 
919 {
920     return countFactories() == 0;
921 }
922
923 ICUServiceKey* 
924 ICUService::createKey(const UnicodeString* id, UErrorCode& status) const 
925 {
926     return (U_FAILURE(status) || id == NULL) ? NULL : new ICUServiceKey(*id);
927 }
928
929 void 
930 ICUService::clearCaches() 
931 {
932     // callers synchronize before use
933     ++timestamp;
934     delete dnCache;
935     dnCache = NULL;
936     delete idCache;
937     idCache = NULL;
938     delete serviceCache; serviceCache = NULL;
939 }
940
941 void 
942 ICUService::clearServiceCache() 
943 {
944     // callers synchronize before use
945     delete serviceCache; serviceCache = NULL;
946 }
947
948 UBool 
949 ICUService::acceptsListener(const EventListener& l) const 
950 {
951     return dynamic_cast<const ServiceListener*>(&l) != NULL;
952 }
953
954 void 
955 ICUService::notifyListener(EventListener& l) const 
956 {
957     ((ServiceListener&)l).serviceChanged(*this);
958 }
959
960 UnicodeString&
961 ICUService::getName(UnicodeString& result) const 
962 {
963     return result.append(name);
964 }
965
966 int32_t 
967 ICUService::countFactories() const 
968 {
969     return factories == NULL ? 0 : factories->size();
970 }
971
972 int32_t
973 ICUService::getTimestamp() const
974 {
975     return timestamp;
976 }
977
978 U_NAMESPACE_END
979
980 /* UCONFIG_NO_SERVICE */
981 #endif