Coverage Report

Created: 2018-09-25 14:53

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