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