/** Reads * keyInfo{ * deprecated{ * kh{"true"} * vt{"true"} * } * valueType{ * ca{"incremental"} * h0{"single"} * kr{"multiple"} * vt{"multiple"} * x0{"any"} * } * } */ private static void GetKeyInfo(UResourceBundle keyInfoRes) { ISet <string> _deprecatedKeys = new JCG.HashSet <string>(); IDictionary <string, KeyTypeDataValueType> _valueTypes = new JCG.LinkedDictionary <string, KeyTypeDataValueType>(); foreach (var keyInfoEntry in keyInfoRes) { string key = keyInfoEntry.Key; KeyInfoType keyInfo = (KeyInfoType)Enum.Parse(typeof(KeyInfoType), key, true); foreach (var keyInfoEntry2 in keyInfoEntry) { string key2 = keyInfoEntry2.Key; string value2 = keyInfoEntry2.GetString(); switch (keyInfo) { case KeyInfoType.deprecated: _deprecatedKeys.Add(key2); break; case KeyInfoType.valueType: _valueTypes[key2] = (KeyTypeDataValueType)Enum.Parse(typeof(KeyTypeDataValueType), value2, true); break; } } } DEPRECATED_KEYS = _deprecatedKeys.AsReadOnly(); VALUE_TYPES = _valueTypes.AsReadOnly(); }
/** Reads: * typeInfo{ * deprecated{ * co{ * direct{"true"} * } * tz{ * camtr{"true"} * } * } * } */ private static void GetTypeInfo(UResourceBundle typeInfoRes) { IDictionary <string, ISet <string> > _deprecatedKeyTypes = new JCG.LinkedDictionary <string, ISet <string> >(); foreach (var keyInfoEntry in typeInfoRes) { string key = keyInfoEntry.Key; TypeInfoType typeInfo = (TypeInfoType)Enum.Parse(typeof(TypeInfoType), key, true); foreach (var keyInfoEntry2 in keyInfoEntry) { string key2 = keyInfoEntry2.Key; ISet <string> _deprecatedTypes = new JCG.LinkedHashSet <string>(); foreach (var keyInfoEntry3 in keyInfoEntry2) { string key3 = keyInfoEntry3.Key; switch (typeInfo) { // allow for expansion case TypeInfoType.deprecated: _deprecatedTypes.Add(key3); break; } } _deprecatedKeyTypes[key2] = _deprecatedTypes.AsReadOnly(); } } DEPRECATED_KEY_TYPES = _deprecatedKeyTypes.AsReadOnly(); }
/// <summary> /// Reloads the internal SPI list. /// Changes to the service list are visible after the method ends, all /// iterators (e.g, from <see cref="AvailableServices"/>,...) stay consistent. /// /// <para/><b>NOTE:</b> Only new service providers are added, existing ones are /// never removed or replaced. /// /// <para/><em>this method is expensive and should only be called for discovery /// of new service providers on the given classpath/classloader!</em> /// </summary> public void Reload() { UninterruptableMonitor.Enter(this); try { IDictionary <string, Type> services = new JCG.LinkedDictionary <string, Type>(this.services); SPIClassIterator <S> loader = SPIClassIterator <S> .Get(); foreach (var service in loader) { string clazzName = service.Name; string name = null; foreach (string suffix in suffixes) { if (clazzName.EndsWith(suffix, StringComparison.Ordinal)) { name = clazzName.Substring(0, clazzName.Length - suffix.Length).ToLowerInvariant(); break; } } if (name is null) { throw ServiceConfigurationError.Create("The class name " + service.Name + " has wrong suffix, allowed are: " + Arrays.ToString(suffixes)); } // only add the first one for each name, later services will be ignored // this allows to place services before others in classpath to make // them used instead of others // // TODO: Should we disallow duplicate names here? // Allowing it may get confusing on collisions, as different packages // could contain same factory class, which is a naming bug! // When changing this be careful to allow reload()! if (!services.ContainsKey(name)) { services.Add(name, service); } } this.services = services.AsReadOnly(); } finally { UninterruptableMonitor.Exit(this); } }
private static void InitFromResourceBundle() { UResourceBundle keyTypeDataRes = UResourceBundle.GetBundleInstance( ICUData.IcuBaseName, "keyTypeData", ICUResourceBundle.IcuDataAssembly); GetKeyInfo(keyTypeDataRes.Get("keyInfo")); GetTypeInfo(keyTypeDataRes.Get("typeInfo")); UResourceBundle keyMapRes = keyTypeDataRes.Get("keyMap"); UResourceBundle typeMapRes = keyTypeDataRes.Get("typeMap"); // alias data is optional UResourceBundle typeAliasRes = null; UResourceBundle bcpTypeAliasRes = null; try { typeAliasRes = keyTypeDataRes.Get("typeAlias"); } catch (MissingManifestResourceException) { // fall through } try { bcpTypeAliasRes = keyTypeDataRes.Get("bcpTypeAlias"); } catch (MissingManifestResourceException) { // fall through } // iterate through keyMap resource using (UResourceBundleEnumerator keyMapItr = keyMapRes.GetEnumerator()) { IDictionary <string, ISet <string> > _Bcp47Keys = new JCG.LinkedDictionary <string, ISet <string> >(); // ICU4N NOTE: As long as we don't delete, Dictionary keeps insertion order the same as LinkedHashMap while (keyMapItr.MoveNext()) { UResourceBundle keyMapEntry = keyMapItr.Current; string legacyKeyId = keyMapEntry.Key; string bcpKeyId = keyMapEntry.GetString(); bool hasSameKey = false; if (bcpKeyId.Length == 0) { // Empty value indicates that BCP key is same with the legacy key. bcpKeyId = legacyKeyId; hasSameKey = true; } ISet <string> _bcp47Types = new JCG.LinkedHashSet <string>(); _Bcp47Keys[bcpKeyId] = _bcp47Types.AsReadOnly(); bool isTZ = legacyKeyId.Equals("timezone"); // reverse type alias map IDictionary <string, ISet <string> > typeAliasMap = null; if (typeAliasRes != null) { UResourceBundle typeAliasResByKey = null; try { typeAliasResByKey = typeAliasRes.Get(legacyKeyId); } catch (MissingManifestResourceException) { // fall through } if (typeAliasResByKey != null) { typeAliasMap = new Dictionary <string, ISet <string> >(); using (UResourceBundleEnumerator typeAliasResItr = typeAliasResByKey.GetEnumerator()) { while (typeAliasResItr.MoveNext()) { UResourceBundle typeAliasDataEntry = typeAliasResItr.Current; string from = typeAliasDataEntry.Key; string to = typeAliasDataEntry.GetString(); if (isTZ) { from = from.Replace(':', '/'); } if (!typeAliasMap.TryGetValue(to, out ISet <string> aliasSet) || aliasSet == null) { aliasSet = new JCG.HashSet <string>(); typeAliasMap[to] = aliasSet; } aliasSet.Add(from); } } } } // reverse bcp type alias map IDictionary <string, ISet <string> > bcpTypeAliasMap = null; if (bcpTypeAliasRes != null) { UResourceBundle bcpTypeAliasResByKey = null; try { bcpTypeAliasResByKey = bcpTypeAliasRes.Get(bcpKeyId); } catch (MissingManifestResourceException) { // fall through } if (bcpTypeAliasResByKey != null) { bcpTypeAliasMap = new Dictionary <string, ISet <string> >(); using (UResourceBundleEnumerator bcpTypeAliasResItr = bcpTypeAliasResByKey.GetEnumerator()) { while (bcpTypeAliasResItr.MoveNext()) { UResourceBundle bcpTypeAliasDataEntry = bcpTypeAliasResItr.Current; string from = bcpTypeAliasDataEntry.Key; string to = bcpTypeAliasDataEntry.GetString(); if (!bcpTypeAliasMap.TryGetValue(to, out ISet <string> aliasSet) || aliasSet == null) { aliasSet = new JCG.HashSet <string>(); bcpTypeAliasMap[to] = aliasSet; } aliasSet.Add(from); } } } } IDictionary <string, Type> typeDataMap = new Dictionary <string, Type>(); ISet <SpecialType> specialTypeSet = null; // look up type map for the key, and walk through the mapping data UResourceBundle typeMapResByKey = null; try { typeMapResByKey = typeMapRes.Get(legacyKeyId); } catch (MissingManifestResourceException) { // type map for each key must exist Debug.Assert(false); } if (typeMapResByKey != null) { using (UResourceBundleEnumerator typeMapResByKeyItr = typeMapResByKey.GetEnumerator()) while (typeMapResByKeyItr.MoveNext()) { UResourceBundle typeMapEntry = typeMapResByKeyItr.Current; string legacyTypeId = typeMapEntry.Key; string bcpTypeId = typeMapEntry.GetString(); // special types char first = legacyTypeId[0]; bool isSpecialType = '9' < first && first < 'a' && bcpTypeId.Length == 0; if (isSpecialType) { if (specialTypeSet == null) { specialTypeSet = new JCG.HashSet <SpecialType>(); } specialTypeSet.Add((SpecialType)Enum.Parse(typeof(SpecialType), legacyTypeId, true)); _bcp47Types.Add(legacyTypeId); continue; } if (isTZ) { // a timezone key uses a colon instead of a slash in the resource. // e.g. America:Los_Angeles legacyTypeId = legacyTypeId.Replace(':', '/'); } bool hasSameType = false; if (bcpTypeId.Length == 0) { // Empty value indicates that BCP type is same with the legacy type. bcpTypeId = legacyTypeId; hasSameType = true; } _bcp47Types.Add(bcpTypeId); // Note: legacy type value should never be // equivalent to bcp type value of a different // type under the same key. So we use a single // map for lookup. Type t = new Type(legacyTypeId, bcpTypeId); typeDataMap[AsciiUtil.ToLower(legacyTypeId)] = t; if (!hasSameType) { typeDataMap[AsciiUtil.ToLower(bcpTypeId)] = t; } // Also put aliases in the map if (typeAliasMap != null) { if (typeAliasMap.TryGetValue(legacyTypeId, out ISet <string> typeAliasSet) && typeAliasSet != null) { foreach (string alias in typeAliasSet) { typeDataMap[AsciiUtil.ToLower(alias)] = t; } } } if (bcpTypeAliasMap != null) { if (bcpTypeAliasMap.TryGetValue(bcpTypeId, out ISet <string> bcpTypeAliasSet) && bcpTypeAliasSet != null) { foreach (string alias in bcpTypeAliasSet) { typeDataMap[AsciiUtil.ToLower(alias)] = t; } } } } } KeyData keyData = new KeyData(legacyKeyId, bcpKeyId, typeDataMap, specialTypeSet); KEYMAP[AsciiUtil.ToLower(legacyKeyId)] = keyData; if (!hasSameKey) { KEYMAP[AsciiUtil.ToLower(bcpKeyId)] = keyData; } } BCP47_KEYS = _Bcp47Keys.AsReadOnly(); } }