1 package org.unicode.cldr.util; 2 3 import java.io.File; 4 import java.util.ArrayList; 5 import java.util.EnumMap; 6 import java.util.LinkedHashSet; 7 import java.util.List; 8 import java.util.Locale; 9 import java.util.Map; 10 import java.util.Set; 11 import java.util.TreeMap; 12 import java.util.concurrent.ConcurrentHashMap; 13 14 import org.unicode.cldr.util.StandardCodes.LstrType; 15 16 import com.google.common.base.Splitter; 17 18 public class Validity { 19 20 public enum Status { 21 regular, special, // for languages only (special codes like mul) 22 macroregion, // regions only (from M.49) 23 deprecated, private_use, // for clients of cldr with prior agreements 24 unknown, invalid; // (anything else) 25 } 26 27 private static final ConcurrentHashMap<String, Validity> cache = new ConcurrentHashMap<>(); 28 29 private final Map<LstrType, Map<Status, Set<String>>> typeToStatusToCodes; 30 private final Map<LstrType, Map<String, Status>> typeToCodeToStatus; 31 getInstance()32 public static Validity getInstance() { 33 return getInstance(CLDRPaths.VALIDITY_DIRECTORY); 34 } 35 getInstance(String validityDirectory)36 public static Validity getInstance(String validityDirectory) { 37 Validity result = cache.get(validityDirectory); 38 if (result == null) { 39 final Validity value = new Validity(validityDirectory); 40 result = cache.putIfAbsent(validityDirectory, value); 41 if (result == null) { 42 result = value; 43 } 44 } 45 return result; 46 } 47 Validity(String validityDirectory)48 private Validity(String validityDirectory) { 49 Splitter space = Splitter.on(PatternCache.get("\\s+")).trimResults().omitEmptyStrings(); 50 Map<LstrType, Map<Status, Set<String>>> data = new EnumMap<>(LstrType.class); 51 Map<LstrType, Map<String, Status>> codeToStatus = new EnumMap<>(LstrType.class); 52 final String basePath = validityDirectory; 53 for (String file : new File(basePath).list()) { 54 if (!file.endsWith(".xml")) { 55 continue; 56 } 57 LstrType type = null; 58 try { 59 type = LstrType.valueOf(file.substring(0, file.length() - 4)); 60 } catch (Exception e) { 61 continue; 62 } 63 List<Pair<String, String>> lineData = new ArrayList<>(); 64 Map<Status, Set<String>> submap = data.get(type); 65 if (submap == null) { 66 data.put(type, submap = new EnumMap<>(Status.class)); 67 } 68 Map<String, Status> subCodeToStatus = codeToStatus.get(type); 69 if (subCodeToStatus == null) { 70 codeToStatus.put(type, subCodeToStatus = new TreeMap<>()); 71 } 72 73 XMLFileReader.loadPathValues(basePath + file, lineData, true); 74 for (Pair<String, String> item : lineData) { 75 XPathParts parts = XPathParts.getFrozenInstance(item.getFirst()); 76 if (!"id".equals(parts.getElement(-1))) { 77 continue; 78 } 79 LstrType typeAttr = LstrType.valueOf(parts.getAttributeValue(-1, "type")); 80 if (typeAttr != type) { 81 throw new IllegalArgumentException("Corrupt value for " + type); 82 } 83 Status subtypeAttr = Status.valueOf(parts.getAttributeValue(-1, "idStatus")); 84 Set<String> set = submap.get(subtypeAttr); 85 if (set == null) { 86 submap.put(subtypeAttr, set = new LinkedHashSet<>()); 87 } 88 for (String value : space.split(item.getSecond())) { 89 if (type == LstrType.subdivision) { 90 value = value.toLowerCase(Locale.ROOT).replace("-", ""); 91 } 92 int dashPos = value.indexOf('~'); 93 if (dashPos < 0) { 94 set.add(value); 95 } else { 96 StringRange.expand(value.substring(0, dashPos), value.substring(dashPos + 1), set); 97 } 98 } 99 for (String code : set) { 100 subCodeToStatus.put(code, subtypeAttr); 101 } 102 } 103 } 104 typeToStatusToCodes = CldrUtility.protectCollectionX(data); 105 typeToCodeToStatus = CldrUtility.protectCollectionX(codeToStatus); 106 } 107 108 /** 109 * 110 * @deprecated Use {@link #getStatusToCodes(LstrType)} 111 */ getData()112 public Map<LstrType, Map<Status, Set<String>>> getData() { 113 return typeToStatusToCodes; 114 } 115 getStatusToCodes(LstrType type)116 public Map<Status, Set<String>> getStatusToCodes(LstrType type) { 117 return typeToStatusToCodes.get(type); 118 } 119 getCodeToStatus(LstrType type)120 public Map<String, Status> getCodeToStatus(LstrType type) { 121 return typeToCodeToStatus.get(type); 122 } 123 } 124