intl/icu/source/common/serv.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/common/serv.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,981 @@
     1.4 +/**
     1.5 +*******************************************************************************
     1.6 +* Copyright (C) 2001-2012, International Business Machines Corporation.
     1.7 +* All Rights Reserved.
     1.8 +*******************************************************************************
     1.9 +*/
    1.10 +
    1.11 +#include "unicode/utypes.h"
    1.12 +
    1.13 +#if !UCONFIG_NO_SERVICE
    1.14 +
    1.15 +#include "serv.h"
    1.16 +#include "umutex.h"
    1.17 +
    1.18 +#undef SERVICE_REFCOUNT
    1.19 +
    1.20 +// in case we use the refcount stuff
    1.21 +
    1.22 +U_NAMESPACE_BEGIN
    1.23 +
    1.24 +/*
    1.25 +******************************************************************
    1.26 +*/
    1.27 +
    1.28 +const UChar ICUServiceKey::PREFIX_DELIMITER = 0x002F;   /* '/' */
    1.29 +
    1.30 +ICUServiceKey::ICUServiceKey(const UnicodeString& id) 
    1.31 +: _id(id) {
    1.32 +}
    1.33 +
    1.34 +ICUServiceKey::~ICUServiceKey() 
    1.35 +{
    1.36 +}
    1.37 +
    1.38 +const UnicodeString& 
    1.39 +ICUServiceKey::getID() const 
    1.40 +{
    1.41 +    return _id;
    1.42 +}
    1.43 +
    1.44 +UnicodeString& 
    1.45 +ICUServiceKey::canonicalID(UnicodeString& result) const 
    1.46 +{
    1.47 +    return result.append(_id);
    1.48 +}
    1.49 +
    1.50 +UnicodeString& 
    1.51 +ICUServiceKey::currentID(UnicodeString& result) const 
    1.52 +{
    1.53 +    return canonicalID(result);
    1.54 +}
    1.55 +
    1.56 +UnicodeString& 
    1.57 +ICUServiceKey::currentDescriptor(UnicodeString& result) const 
    1.58 +{
    1.59 +    prefix(result);
    1.60 +    result.append(PREFIX_DELIMITER);
    1.61 +    return currentID(result);
    1.62 +}
    1.63 +
    1.64 +UBool 
    1.65 +ICUServiceKey::fallback() 
    1.66 +{
    1.67 +    return FALSE;
    1.68 +}
    1.69 +
    1.70 +UBool 
    1.71 +ICUServiceKey::isFallbackOf(const UnicodeString& id) const 
    1.72 +{
    1.73 +    return id == _id;
    1.74 +}
    1.75 +
    1.76 +UnicodeString& 
    1.77 +ICUServiceKey::prefix(UnicodeString& result) const 
    1.78 +{
    1.79 +    return result;
    1.80 +}
    1.81 +
    1.82 +UnicodeString& 
    1.83 +ICUServiceKey::parsePrefix(UnicodeString& result) 
    1.84 +{
    1.85 +    int32_t n = result.indexOf(PREFIX_DELIMITER);
    1.86 +    if (n < 0) {
    1.87 +        n = 0;
    1.88 +    }
    1.89 +    result.remove(n);
    1.90 +    return result;
    1.91 +}
    1.92 +
    1.93 +UnicodeString& 
    1.94 +ICUServiceKey::parseSuffix(UnicodeString& result) 
    1.95 +{
    1.96 +    int32_t n = result.indexOf(PREFIX_DELIMITER);
    1.97 +    if (n >= 0) {
    1.98 +        result.remove(0, n+1);
    1.99 +    }
   1.100 +    return result;
   1.101 +}
   1.102 +
   1.103 +#ifdef SERVICE_DEBUG
   1.104 +UnicodeString& 
   1.105 +ICUServiceKey::debug(UnicodeString& result) const 
   1.106 +{
   1.107 +    debugClass(result);
   1.108 +    result.append(" id: ");
   1.109 +    result.append(_id);
   1.110 +    return result;
   1.111 +}
   1.112 +
   1.113 +UnicodeString& 
   1.114 +ICUServiceKey::debugClass(UnicodeString& result) const 
   1.115 +{
   1.116 +    return result.append("ICUServiceKey");
   1.117 +}
   1.118 +#endif
   1.119 +
   1.120 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUServiceKey)
   1.121 +
   1.122 +/*
   1.123 +******************************************************************
   1.124 +*/
   1.125 +
   1.126 +ICUServiceFactory::~ICUServiceFactory() {}
   1.127 +
   1.128 +SimpleFactory::SimpleFactory(UObject* instanceToAdopt, const UnicodeString& id, UBool visible) 
   1.129 +: _instance(instanceToAdopt), _id(id), _visible(visible)
   1.130 +{
   1.131 +}
   1.132 +
   1.133 +SimpleFactory::~SimpleFactory() 
   1.134 +{
   1.135 +    delete _instance;
   1.136 +}
   1.137 +
   1.138 +UObject* 
   1.139 +SimpleFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const 
   1.140 +{
   1.141 +    if (U_SUCCESS(status)) {
   1.142 +        UnicodeString temp;
   1.143 +        if (_id == key.currentID(temp)) {
   1.144 +            return service->cloneInstance(_instance); 
   1.145 +        }
   1.146 +    }
   1.147 +    return NULL;
   1.148 +}
   1.149 +
   1.150 +void 
   1.151 +SimpleFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const 
   1.152 +{
   1.153 +    if (_visible) {
   1.154 +        result.put(_id, (void*)this, status); // cast away const
   1.155 +    } else {
   1.156 +        result.remove(_id);
   1.157 +    }
   1.158 +}
   1.159 +
   1.160 +UnicodeString& 
   1.161 +SimpleFactory::getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const 
   1.162 +{
   1.163 +    if (_visible && _id == id) {
   1.164 +        result = _id;
   1.165 +    } else {
   1.166 +        result.setToBogus();
   1.167 +    }
   1.168 +    return result;
   1.169 +}
   1.170 +
   1.171 +#ifdef SERVICE_DEBUG
   1.172 +UnicodeString& 
   1.173 +SimpleFactory::debug(UnicodeString& toAppendTo) const 
   1.174 +{
   1.175 +    debugClass(toAppendTo);
   1.176 +    toAppendTo.append(" id: ");
   1.177 +    toAppendTo.append(_id);
   1.178 +    toAppendTo.append(", visible: ");
   1.179 +    toAppendTo.append(_visible ? "T" : "F");
   1.180 +    return toAppendTo;
   1.181 +}
   1.182 +
   1.183 +UnicodeString& 
   1.184 +SimpleFactory::debugClass(UnicodeString& toAppendTo) const 
   1.185 +{
   1.186 +    return toAppendTo.append("SimpleFactory");
   1.187 +}
   1.188 +#endif
   1.189 +
   1.190 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleFactory)
   1.191 +
   1.192 +/*
   1.193 +******************************************************************
   1.194 +*/
   1.195 +
   1.196 +ServiceListener::~ServiceListener() {}
   1.197 +
   1.198 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceListener)
   1.199 +
   1.200 +/*
   1.201 +******************************************************************
   1.202 +*/
   1.203 +
   1.204 +// Record the actual id for this service in the cache, so we can return it
   1.205 +// even if we succeed later with a different id.
   1.206 +class CacheEntry : public UMemory {
   1.207 +private:
   1.208 +    int32_t refcount;
   1.209 +
   1.210 +public:
   1.211 +    UnicodeString actualDescriptor;
   1.212 +    UObject* service;
   1.213 +
   1.214 +    /**
   1.215 +    * Releases a reference to the shared resource.
   1.216 +    */
   1.217 +    ~CacheEntry() {
   1.218 +        delete service;
   1.219 +    }
   1.220 +
   1.221 +    CacheEntry(const UnicodeString& _actualDescriptor, UObject* _service) 
   1.222 +        : refcount(1), actualDescriptor(_actualDescriptor), service(_service) {
   1.223 +    }
   1.224 +
   1.225 +    /**
   1.226 +    * Instantiation creates an initial reference, so don't call this
   1.227 +    * unless you're creating a new pointer to this.  Management of
   1.228 +    * that pointer will have to know how to deal with refcounts.  
   1.229 +    * Return true if the resource has not already been released.
   1.230 +    */
   1.231 +    CacheEntry* ref() {
   1.232 +        ++refcount;
   1.233 +        return this;
   1.234 +    }
   1.235 +
   1.236 +    /**
   1.237 +    * Destructions removes a reference, so don't call this unless
   1.238 +    * you're removing pointer to this somewhere.  Management of that
   1.239 +    * pointer will have to know how to deal with refcounts.  Once
   1.240 +    * the refcount drops to zero, the resource is released.  Return
   1.241 +    * false if the resouce has been released.
   1.242 +    */
   1.243 +    CacheEntry* unref() {
   1.244 +        if ((--refcount) == 0) {
   1.245 +            delete this;
   1.246 +            return NULL;
   1.247 +        }
   1.248 +        return this;
   1.249 +    }
   1.250 +
   1.251 +    /**
   1.252 +    * Return TRUE if there is at least one reference to this and the
   1.253 +    * resource has not been released.
   1.254 +    */
   1.255 +    UBool isShared() const {
   1.256 +        return refcount > 1;
   1.257 +    }
   1.258 +};
   1.259 +
   1.260 +// UObjectDeleter for serviceCache
   1.261 +U_CDECL_BEGIN
   1.262 +static void U_CALLCONV
   1.263 +cacheDeleter(void* obj) {
   1.264 +    U_NAMESPACE_USE ((CacheEntry*)obj)->unref();
   1.265 +}
   1.266 +
   1.267 +/**
   1.268 +* Deleter for UObjects
   1.269 +*/
   1.270 +static void U_CALLCONV
   1.271 +deleteUObject(void *obj) {
   1.272 +    U_NAMESPACE_USE delete (UObject*) obj;
   1.273 +}
   1.274 +U_CDECL_END
   1.275 +
   1.276 +/*
   1.277 +******************************************************************
   1.278 +*/
   1.279 +
   1.280 +class DNCache : public UMemory {
   1.281 +public:
   1.282 +    Hashtable cache;
   1.283 +    const Locale locale;
   1.284 +
   1.285 +    DNCache(const Locale& _locale) 
   1.286 +        : cache(), locale(_locale) 
   1.287 +    {
   1.288 +        // cache.setKeyDeleter(uprv_deleteUObject);
   1.289 +    }
   1.290 +};
   1.291 +
   1.292 +
   1.293 +/*
   1.294 +******************************************************************
   1.295 +*/
   1.296 +
   1.297 +StringPair* 
   1.298 +StringPair::create(const UnicodeString& displayName, 
   1.299 +                   const UnicodeString& id,
   1.300 +                   UErrorCode& status)
   1.301 +{
   1.302 +    if (U_SUCCESS(status)) {
   1.303 +        StringPair* sp = new StringPair(displayName, id);
   1.304 +        if (sp == NULL || sp->isBogus()) {
   1.305 +            status = U_MEMORY_ALLOCATION_ERROR;
   1.306 +            delete sp;
   1.307 +            return NULL;
   1.308 +        }
   1.309 +        return sp;
   1.310 +    }
   1.311 +    return NULL;
   1.312 +}
   1.313 +
   1.314 +UBool 
   1.315 +StringPair::isBogus() const {
   1.316 +    return displayName.isBogus() || id.isBogus();
   1.317 +}
   1.318 +
   1.319 +StringPair::StringPair(const UnicodeString& _displayName, 
   1.320 +                       const UnicodeString& _id)
   1.321 +: displayName(_displayName)
   1.322 +, id(_id)
   1.323 +{
   1.324 +}
   1.325 +
   1.326 +U_CDECL_BEGIN
   1.327 +static void U_CALLCONV
   1.328 +userv_deleteStringPair(void *obj) {
   1.329 +    U_NAMESPACE_USE delete (StringPair*) obj;
   1.330 +}
   1.331 +U_CDECL_END
   1.332 +
   1.333 +/*
   1.334 +******************************************************************
   1.335 +*/
   1.336 +
   1.337 +static UMutex lock = U_MUTEX_INITIALIZER;
   1.338 +
   1.339 +ICUService::ICUService()
   1.340 +: name()
   1.341 +, timestamp(0)
   1.342 +, factories(NULL)
   1.343 +, serviceCache(NULL)
   1.344 +, idCache(NULL)
   1.345 +, dnCache(NULL)
   1.346 +{
   1.347 +}
   1.348 +
   1.349 +ICUService::ICUService(const UnicodeString& newName) 
   1.350 +: name(newName)
   1.351 +, timestamp(0)
   1.352 +, factories(NULL)
   1.353 +, serviceCache(NULL)
   1.354 +, idCache(NULL)
   1.355 +, dnCache(NULL)
   1.356 +{
   1.357 +}
   1.358 +
   1.359 +ICUService::~ICUService()
   1.360 +{
   1.361 +    {
   1.362 +        Mutex mutex(&lock);
   1.363 +        clearCaches();
   1.364 +        delete factories;
   1.365 +        factories = NULL;
   1.366 +    }
   1.367 +}
   1.368 +
   1.369 +UObject* 
   1.370 +ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const 
   1.371 +{
   1.372 +    return get(descriptor, NULL, status);
   1.373 +}
   1.374 +
   1.375 +UObject* 
   1.376 +ICUService::get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const 
   1.377 +{
   1.378 +    UObject* result = NULL;
   1.379 +    ICUServiceKey* key = createKey(&descriptor, status);
   1.380 +    if (key) {
   1.381 +        result = getKey(*key, actualReturn, status);
   1.382 +        delete key;
   1.383 +    }
   1.384 +    return result;
   1.385 +}
   1.386 +
   1.387 +UObject* 
   1.388 +ICUService::getKey(ICUServiceKey& key, UErrorCode& status) const 
   1.389 +{
   1.390 +    return getKey(key, NULL, status);
   1.391 +}
   1.392 +
   1.393 +// this is a vector that subclasses of ICUService can override to further customize the result object
   1.394 +// before returning it.  All other public get functions should call this one.
   1.395 +
   1.396 +UObject* 
   1.397 +ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const 
   1.398 +{
   1.399 +    return getKey(key, actualReturn, NULL, status);
   1.400 +}
   1.401 +
   1.402 +// make it possible to call reentrantly on systems that don't have reentrant mutexes.
   1.403 +// we can use this simple approach since we know the situation where we're calling
   1.404 +// reentrantly even without knowing the thread.
   1.405 +class XMutex : public UMemory {
   1.406 +public:
   1.407 +    inline XMutex(UMutex *mutex, UBool reentering) 
   1.408 +        : fMutex(mutex)
   1.409 +        , fActive(!reentering) 
   1.410 +    {
   1.411 +        if (fActive) umtx_lock(fMutex);
   1.412 +    }
   1.413 +    inline ~XMutex() {
   1.414 +        if (fActive) umtx_unlock(fMutex);
   1.415 +    }
   1.416 +
   1.417 +private:
   1.418 +    UMutex  *fMutex;
   1.419 +    UBool fActive;
   1.420 +};
   1.421 +
   1.422 +struct UVectorDeleter {
   1.423 +    UVector* _obj;
   1.424 +    UVectorDeleter() : _obj(NULL) {}
   1.425 +    ~UVectorDeleter() { delete _obj; }
   1.426 +};
   1.427 +
   1.428 +// called only by factories, treat as private
   1.429 +UObject* 
   1.430 +ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUServiceFactory* factory, UErrorCode& status) const 
   1.431 +{
   1.432 +    if (U_FAILURE(status)) {
   1.433 +        return NULL;
   1.434 +    }
   1.435 +
   1.436 +    if (isDefault()) {
   1.437 +        return handleDefault(key, actualReturn, status);
   1.438 +    }
   1.439 +
   1.440 +    ICUService* ncthis = (ICUService*)this; // cast away semantic const
   1.441 +
   1.442 +    CacheEntry* result = NULL;
   1.443 +    {
   1.444 +        // The factory list can't be modified until we're done, 
   1.445 +        // otherwise we might update the cache with an invalid result.
   1.446 +        // The cache has to stay in synch with the factory list.
   1.447 +        // ICU doesn't have monitors so we can't use rw locks, so 
   1.448 +        // we single-thread everything using this service, for now.
   1.449 +
   1.450 +        // if factory is not null, we're calling from within the mutex,
   1.451 +        // and since some unix machines don't have reentrant mutexes we
   1.452 +        // need to make sure not to try to lock it again.
   1.453 +        XMutex mutex(&lock, factory != NULL);
   1.454 +
   1.455 +        if (serviceCache == NULL) {
   1.456 +            ncthis->serviceCache = new Hashtable(status);
   1.457 +            if (ncthis->serviceCache == NULL) {
   1.458 +                return NULL;
   1.459 +            }
   1.460 +            if (U_FAILURE(status)) {
   1.461 +                delete serviceCache;
   1.462 +                return NULL;
   1.463 +            }
   1.464 +            serviceCache->setValueDeleter(cacheDeleter);
   1.465 +        }
   1.466 +
   1.467 +        UnicodeString currentDescriptor;
   1.468 +        UVectorDeleter cacheDescriptorList;
   1.469 +        UBool putInCache = FALSE;
   1.470 +
   1.471 +        int32_t startIndex = 0;
   1.472 +        int32_t limit = factories->size();
   1.473 +        UBool cacheResult = TRUE;
   1.474 +
   1.475 +        if (factory != NULL) {
   1.476 +            for (int32_t i = 0; i < limit; ++i) {
   1.477 +                if (factory == (const ICUServiceFactory*)factories->elementAt(i)) {
   1.478 +                    startIndex = i + 1;
   1.479 +                    break;
   1.480 +                }
   1.481 +            }
   1.482 +            if (startIndex == 0) {
   1.483 +                // throw new InternalError("Factory " + factory + "not registered with service: " + this);
   1.484 +                status = U_ILLEGAL_ARGUMENT_ERROR;
   1.485 +                return NULL;
   1.486 +            }
   1.487 +            cacheResult = FALSE;
   1.488 +        }
   1.489 +
   1.490 +        do {
   1.491 +            currentDescriptor.remove();
   1.492 +            key.currentDescriptor(currentDescriptor);
   1.493 +            result = (CacheEntry*)serviceCache->get(currentDescriptor);
   1.494 +            if (result != NULL) {
   1.495 +                break;
   1.496 +            }
   1.497 +
   1.498 +            // first test of cache failed, so we'll have to update
   1.499 +            // the cache if we eventually succeed-- that is, if we're 
   1.500 +            // going to update the cache at all.
   1.501 +            putInCache = TRUE;
   1.502 +
   1.503 +            int32_t index = startIndex;
   1.504 +            while (index < limit) {
   1.505 +                ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(index++);
   1.506 +                UObject* service = f->create(key, this, status);
   1.507 +                if (U_FAILURE(status)) {
   1.508 +                    delete service;
   1.509 +                    return NULL;
   1.510 +                }
   1.511 +                if (service != NULL) {
   1.512 +                    result = new CacheEntry(currentDescriptor, service);
   1.513 +                    if (result == NULL) {
   1.514 +                        delete service;
   1.515 +                        status = U_MEMORY_ALLOCATION_ERROR;
   1.516 +                        return NULL;
   1.517 +                    }
   1.518 +
   1.519 +                    goto outerEnd;
   1.520 +                }
   1.521 +            }
   1.522 +
   1.523 +            // prepare to load the cache with all additional ids that 
   1.524 +            // will resolve to result, assuming we'll succeed.  We
   1.525 +            // don't want to keep querying on an id that's going to
   1.526 +            // fallback to the one that succeeded, we want to hit the
   1.527 +            // cache the first time next goaround.
   1.528 +            if (cacheDescriptorList._obj == NULL) {
   1.529 +                cacheDescriptorList._obj = new UVector(uprv_deleteUObject, NULL, 5, status);
   1.530 +                if (U_FAILURE(status)) {
   1.531 +                    return NULL;
   1.532 +                }
   1.533 +            }
   1.534 +            UnicodeString* idToCache = new UnicodeString(currentDescriptor);
   1.535 +            if (idToCache == NULL || idToCache->isBogus()) {
   1.536 +                status = U_MEMORY_ALLOCATION_ERROR;
   1.537 +                return NULL;
   1.538 +            }
   1.539 +
   1.540 +            cacheDescriptorList._obj->addElement(idToCache, status);
   1.541 +            if (U_FAILURE(status)) {
   1.542 +                return NULL;
   1.543 +            }
   1.544 +        } while (key.fallback());
   1.545 +outerEnd:
   1.546 +
   1.547 +        if (result != NULL) {
   1.548 +            if (putInCache && cacheResult) {
   1.549 +                serviceCache->put(result->actualDescriptor, result, status);
   1.550 +                if (U_FAILURE(status)) {
   1.551 +                    delete result;
   1.552 +                    return NULL;
   1.553 +                }
   1.554 +
   1.555 +                if (cacheDescriptorList._obj != NULL) {
   1.556 +                    for (int32_t i = cacheDescriptorList._obj->size(); --i >= 0;) {
   1.557 +                        UnicodeString* desc = (UnicodeString*)cacheDescriptorList._obj->elementAt(i);
   1.558 +                        serviceCache->put(*desc, result, status);
   1.559 +                        if (U_FAILURE(status)) {
   1.560 +                            delete result;
   1.561 +                            return NULL;
   1.562 +                        }
   1.563 +
   1.564 +                        result->ref();
   1.565 +                        cacheDescriptorList._obj->removeElementAt(i);
   1.566 +                    }
   1.567 +                }
   1.568 +            }
   1.569 +
   1.570 +            if (actualReturn != NULL) {
   1.571 +                // strip null prefix
   1.572 +                if (result->actualDescriptor.indexOf((UChar)0x2f) == 0) { // U+002f=slash (/)
   1.573 +                    actualReturn->remove();
   1.574 +                    actualReturn->append(result->actualDescriptor, 
   1.575 +                        1, 
   1.576 +                        result->actualDescriptor.length() - 1);
   1.577 +                } else {
   1.578 +                    *actualReturn = result->actualDescriptor;
   1.579 +                }
   1.580 +
   1.581 +                if (actualReturn->isBogus()) {
   1.582 +                    status = U_MEMORY_ALLOCATION_ERROR;
   1.583 +                    delete result;
   1.584 +                    return NULL;
   1.585 +                }
   1.586 +            }
   1.587 +
   1.588 +            UObject* service = cloneInstance(result->service);
   1.589 +            if (putInCache && !cacheResult) {
   1.590 +                delete result;
   1.591 +            }
   1.592 +            return service;
   1.593 +        }
   1.594 +    }
   1.595 +
   1.596 +    return handleDefault(key, actualReturn, status);
   1.597 +}
   1.598 +
   1.599 +UObject* 
   1.600 +ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const 
   1.601 +{
   1.602 +    return NULL;
   1.603 +}
   1.604 +
   1.605 +UVector& 
   1.606 +ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const {
   1.607 +    return getVisibleIDs(result, NULL, status);
   1.608 +}
   1.609 +
   1.610 +UVector& 
   1.611 +ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const 
   1.612 +{
   1.613 +    result.removeAllElements();
   1.614 +
   1.615 +    if (U_FAILURE(status)) {
   1.616 +        return result;
   1.617 +    }
   1.618 +
   1.619 +    {
   1.620 +        Mutex mutex(&lock);
   1.621 +        const Hashtable* map = getVisibleIDMap(status);
   1.622 +        if (map != NULL) {
   1.623 +            ICUServiceKey* fallbackKey = createKey(matchID, status);
   1.624 +
   1.625 +            for (int32_t pos = -1;;) {
   1.626 +                const UHashElement* e = map->nextElement(pos);
   1.627 +                if (e == NULL) {
   1.628 +                    break;
   1.629 +                }
   1.630 +
   1.631 +                const UnicodeString* id = (const UnicodeString*)e->key.pointer;
   1.632 +                if (fallbackKey != NULL) {
   1.633 +                    if (!fallbackKey->isFallbackOf(*id)) {
   1.634 +                        continue;
   1.635 +                    }
   1.636 +                }
   1.637 +
   1.638 +                UnicodeString* idClone = new UnicodeString(*id);
   1.639 +                if (idClone == NULL || idClone->isBogus()) {
   1.640 +                    delete idClone;
   1.641 +                    status = U_MEMORY_ALLOCATION_ERROR;
   1.642 +                    break;
   1.643 +                }
   1.644 +                result.addElement(idClone, status);
   1.645 +                if (U_FAILURE(status)) {
   1.646 +                    delete idClone;
   1.647 +                    break;
   1.648 +                }
   1.649 +            }
   1.650 +            delete fallbackKey;
   1.651 +        }
   1.652 +    }
   1.653 +    if (U_FAILURE(status)) {
   1.654 +        result.removeAllElements();
   1.655 +    }
   1.656 +    return result;
   1.657 +}
   1.658 +
   1.659 +const Hashtable* 
   1.660 +ICUService::getVisibleIDMap(UErrorCode& status) const {
   1.661 +    if (U_FAILURE(status)) return NULL;
   1.662 +
   1.663 +    // must only be called when lock is already held
   1.664 +
   1.665 +    ICUService* ncthis = (ICUService*)this; // cast away semantic const
   1.666 +    if (idCache == NULL) {
   1.667 +        ncthis->idCache = new Hashtable(status);
   1.668 +        if (idCache == NULL) {
   1.669 +            status = U_MEMORY_ALLOCATION_ERROR;
   1.670 +        } else if (factories != NULL) {
   1.671 +            for (int32_t pos = factories->size(); --pos >= 0;) {
   1.672 +                ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(pos);
   1.673 +                f->updateVisibleIDs(*idCache, status);
   1.674 +            }
   1.675 +            if (U_FAILURE(status)) {
   1.676 +                delete idCache;
   1.677 +                ncthis->idCache = NULL;
   1.678 +            }
   1.679 +        }
   1.680 +    }
   1.681 +
   1.682 +    return idCache;
   1.683 +}
   1.684 +
   1.685 +
   1.686 +UnicodeString& 
   1.687 +ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const 
   1.688 +{
   1.689 +    return getDisplayName(id, result, Locale::getDefault());
   1.690 +}
   1.691 +
   1.692 +UnicodeString& 
   1.693 +ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const 
   1.694 +{
   1.695 +    {
   1.696 +        UErrorCode status = U_ZERO_ERROR;
   1.697 +        Mutex mutex(&lock);
   1.698 +        const Hashtable* map = getVisibleIDMap(status);
   1.699 +        if (map != NULL) {
   1.700 +            ICUServiceFactory* f = (ICUServiceFactory*)map->get(id);
   1.701 +            if (f != NULL) {
   1.702 +                f->getDisplayName(id, locale, result);
   1.703 +                return result;
   1.704 +            }
   1.705 +
   1.706 +            // fallback
   1.707 +            UErrorCode status = U_ZERO_ERROR;
   1.708 +            ICUServiceKey* fallbackKey = createKey(&id, status);
   1.709 +            while (fallbackKey->fallback()) {
   1.710 +                UnicodeString us;
   1.711 +                fallbackKey->currentID(us);
   1.712 +                f = (ICUServiceFactory*)map->get(us);
   1.713 +                if (f != NULL) {
   1.714 +                    f->getDisplayName(id, locale, result);
   1.715 +                    delete fallbackKey;
   1.716 +                    return result;
   1.717 +                }
   1.718 +            }
   1.719 +            delete fallbackKey;
   1.720 +        }
   1.721 +    }
   1.722 +    result.setToBogus();
   1.723 +    return result;
   1.724 +}
   1.725 +
   1.726 +UVector& 
   1.727 +ICUService::getDisplayNames(UVector& result, UErrorCode& status) const 
   1.728 +{
   1.729 +    return getDisplayNames(result, Locale::getDefault(), NULL, status);
   1.730 +}
   1.731 +
   1.732 +
   1.733 +UVector& 
   1.734 +ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const 
   1.735 +{
   1.736 +    return getDisplayNames(result, locale, NULL, status);
   1.737 +}
   1.738 +
   1.739 +UVector& 
   1.740 +ICUService::getDisplayNames(UVector& result, 
   1.741 +                            const Locale& locale, 
   1.742 +                            const UnicodeString* matchID, 
   1.743 +                            UErrorCode& status) const 
   1.744 +{
   1.745 +    result.removeAllElements();
   1.746 +    result.setDeleter(userv_deleteStringPair);
   1.747 +    if (U_SUCCESS(status)) {
   1.748 +        ICUService* ncthis = (ICUService*)this; // cast away semantic const
   1.749 +        Mutex mutex(&lock);
   1.750 +
   1.751 +        if (dnCache != NULL && dnCache->locale != locale) {
   1.752 +            delete dnCache;
   1.753 +            ncthis->dnCache = NULL;
   1.754 +        }
   1.755 +
   1.756 +        if (dnCache == NULL) {
   1.757 +            const Hashtable* m = getVisibleIDMap(status);
   1.758 +            if (U_FAILURE(status)) {
   1.759 +                return result;
   1.760 +            }
   1.761 +            ncthis->dnCache = new DNCache(locale); 
   1.762 +            if (dnCache == NULL) {
   1.763 +                status = U_MEMORY_ALLOCATION_ERROR;
   1.764 +                return result;
   1.765 +            }
   1.766 +
   1.767 +            int32_t pos = -1;
   1.768 +            const UHashElement* entry = NULL;
   1.769 +            while ((entry = m->nextElement(pos)) != NULL) {
   1.770 +                const UnicodeString* id = (const UnicodeString*)entry->key.pointer;
   1.771 +                ICUServiceFactory* f = (ICUServiceFactory*)entry->value.pointer;
   1.772 +                UnicodeString dname;
   1.773 +                f->getDisplayName(*id, locale, dname);
   1.774 +                if (dname.isBogus()) {
   1.775 +                    status = U_MEMORY_ALLOCATION_ERROR;
   1.776 +                } else {
   1.777 +                    dnCache->cache.put(dname, (void*)id, status); // share pointer with visibleIDMap
   1.778 +                    if (U_SUCCESS(status)) {
   1.779 +                        continue;
   1.780 +                    }
   1.781 +                }
   1.782 +                delete dnCache;
   1.783 +                ncthis->dnCache = NULL;
   1.784 +                return result;
   1.785 +            }
   1.786 +        }
   1.787 +    }
   1.788 +
   1.789 +    ICUServiceKey* matchKey = createKey(matchID, status);
   1.790 +    /* To ensure that all elements in the hashtable are iterated, set pos to -1.
   1.791 +     * nextElement(pos) will skip the position at pos and begin the iteration
   1.792 +     * at the next position, which in this case will be 0.
   1.793 +     */
   1.794 +    int32_t pos = -1; 
   1.795 +    const UHashElement *entry = NULL;
   1.796 +    while ((entry = dnCache->cache.nextElement(pos)) != NULL) {
   1.797 +        const UnicodeString* id = (const UnicodeString*)entry->value.pointer;
   1.798 +        if (matchKey != NULL && !matchKey->isFallbackOf(*id)) {
   1.799 +            continue;
   1.800 +        }
   1.801 +        const UnicodeString* dn = (const UnicodeString*)entry->key.pointer;
   1.802 +        StringPair* sp = StringPair::create(*id, *dn, status);
   1.803 +        result.addElement(sp, status);
   1.804 +        if (U_FAILURE(status)) {
   1.805 +            result.removeAllElements();
   1.806 +            break;
   1.807 +        }
   1.808 +    }
   1.809 +    delete matchKey;
   1.810 +
   1.811 +    return result;
   1.812 +}
   1.813 +
   1.814 +URegistryKey
   1.815 +ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status) 
   1.816 +{
   1.817 +    return registerInstance(objToAdopt, id, TRUE, status);
   1.818 +}
   1.819 +
   1.820 +URegistryKey
   1.821 +ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status) 
   1.822 +{
   1.823 +    ICUServiceKey* key = createKey(&id, status);
   1.824 +    if (key != NULL) {
   1.825 +        UnicodeString canonicalID;
   1.826 +        key->canonicalID(canonicalID);
   1.827 +        delete key;
   1.828 +
   1.829 +        ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status);
   1.830 +        if (f != NULL) {
   1.831 +            return registerFactory(f, status);
   1.832 +        }
   1.833 +    }
   1.834 +    delete objToAdopt;
   1.835 +    return NULL;
   1.836 +}
   1.837 +
   1.838 +ICUServiceFactory* 
   1.839 +ICUService::createSimpleFactory(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
   1.840 +{
   1.841 +    if (U_SUCCESS(status)) {
   1.842 +        if ((objToAdopt != NULL) && (!id.isBogus())) {
   1.843 +            return new SimpleFactory(objToAdopt, id, visible);
   1.844 +        }
   1.845 +        status = U_ILLEGAL_ARGUMENT_ERROR;
   1.846 +    }
   1.847 +    return NULL;
   1.848 +}
   1.849 +
   1.850 +URegistryKey
   1.851 +ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status) 
   1.852 +{
   1.853 +    if (U_SUCCESS(status) && factoryToAdopt != NULL) {
   1.854 +        Mutex mutex(&lock);
   1.855 +
   1.856 +        if (factories == NULL) {
   1.857 +            factories = new UVector(deleteUObject, NULL, status);
   1.858 +            if (U_FAILURE(status)) {
   1.859 +                delete factories;
   1.860 +                return NULL;
   1.861 +            }
   1.862 +        }
   1.863 +        factories->insertElementAt(factoryToAdopt, 0, status);
   1.864 +        if (U_SUCCESS(status)) {
   1.865 +            clearCaches();
   1.866 +        } else {
   1.867 +            delete factoryToAdopt;
   1.868 +            factoryToAdopt = NULL;
   1.869 +        }
   1.870 +    }
   1.871 +
   1.872 +    if (factoryToAdopt != NULL) {
   1.873 +        notifyChanged();
   1.874 +    }
   1.875 +
   1.876 +    return (URegistryKey)factoryToAdopt;
   1.877 +}
   1.878 +
   1.879 +UBool 
   1.880 +ICUService::unregister(URegistryKey rkey, UErrorCode& status) 
   1.881 +{
   1.882 +    ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
   1.883 +    UBool result = FALSE;
   1.884 +    if (factory != NULL && factories != NULL) {
   1.885 +        Mutex mutex(&lock);
   1.886 +
   1.887 +        if (factories->removeElement(factory)) {
   1.888 +            clearCaches();
   1.889 +            result = TRUE;
   1.890 +        } else {
   1.891 +            status = U_ILLEGAL_ARGUMENT_ERROR;
   1.892 +            delete factory;
   1.893 +        }
   1.894 +    }
   1.895 +    if (result) {
   1.896 +        notifyChanged();
   1.897 +    }
   1.898 +    return result;
   1.899 +}
   1.900 +
   1.901 +void 
   1.902 +ICUService::reset() 
   1.903 +{
   1.904 +    {
   1.905 +        Mutex mutex(&lock);
   1.906 +        reInitializeFactories();
   1.907 +        clearCaches();
   1.908 +    }
   1.909 +    notifyChanged();
   1.910 +}
   1.911 +
   1.912 +void 
   1.913 +ICUService::reInitializeFactories() 
   1.914 +{
   1.915 +    if (factories != NULL) {
   1.916 +        factories->removeAllElements();
   1.917 +    }
   1.918 +}
   1.919 +
   1.920 +UBool 
   1.921 +ICUService::isDefault() const 
   1.922 +{
   1.923 +    return countFactories() == 0;
   1.924 +}
   1.925 +
   1.926 +ICUServiceKey* 
   1.927 +ICUService::createKey(const UnicodeString* id, UErrorCode& status) const 
   1.928 +{
   1.929 +    return (U_FAILURE(status) || id == NULL) ? NULL : new ICUServiceKey(*id);
   1.930 +}
   1.931 +
   1.932 +void 
   1.933 +ICUService::clearCaches() 
   1.934 +{
   1.935 +    // callers synchronize before use
   1.936 +    ++timestamp;
   1.937 +    delete dnCache;
   1.938 +    dnCache = NULL;
   1.939 +    delete idCache;
   1.940 +    idCache = NULL;
   1.941 +    delete serviceCache; serviceCache = NULL;
   1.942 +}
   1.943 +
   1.944 +void 
   1.945 +ICUService::clearServiceCache() 
   1.946 +{
   1.947 +    // callers synchronize before use
   1.948 +    delete serviceCache; serviceCache = NULL;
   1.949 +}
   1.950 +
   1.951 +UBool 
   1.952 +ICUService::acceptsListener(const EventListener& l) const 
   1.953 +{
   1.954 +    return dynamic_cast<const ServiceListener*>(&l) != NULL;
   1.955 +}
   1.956 +
   1.957 +void 
   1.958 +ICUService::notifyListener(EventListener& l) const 
   1.959 +{
   1.960 +    ((ServiceListener&)l).serviceChanged(*this);
   1.961 +}
   1.962 +
   1.963 +UnicodeString&
   1.964 +ICUService::getName(UnicodeString& result) const 
   1.965 +{
   1.966 +    return result.append(name);
   1.967 +}
   1.968 +
   1.969 +int32_t 
   1.970 +ICUService::countFactories() const 
   1.971 +{
   1.972 +    return factories == NULL ? 0 : factories->size();
   1.973 +}
   1.974 +
   1.975 +int32_t
   1.976 +ICUService::getTimestamp() const
   1.977 +{
   1.978 +    return timestamp;
   1.979 +}
   1.980 +
   1.981 +U_NAMESPACE_END
   1.982 +
   1.983 +/* UCONFIG_NO_SERVICE */
   1.984 +#endif

mercurial