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