• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, reserved, 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 
54         File validityDir = new File(basePath);
55         if (!validityDir.isDirectory()) {
56             throw new IllegalArgumentException("Not a directory: " + validityDir.getAbsolutePath());
57         }
58         for (String file : validityDir.list()) {
59             if (!file.endsWith(".xml")) {
60                 continue;
61             }
62             LstrType type = null;
63             try {
64                 type = LstrType.fromString(file.substring(0, file.length() - 4));
65             } catch (Exception e) {
66                 continue;
67             }
68             List<Pair<String, String>> lineData = new ArrayList<>();
69             Map<Status, Set<String>> submap = data.get(type);
70             if (submap == null) {
71                 data.put(type, submap = new EnumMap<>(Status.class));
72             }
73             Map<String, Status> subCodeToStatus = codeToStatus.get(type);
74             if (subCodeToStatus == null) {
75                 codeToStatus.put(type, subCodeToStatus = new TreeMap<>());
76             }
77 
78             XMLFileReader.loadPathValues(basePath + file, lineData, true);
79             for (Pair<String, String> item : lineData) {
80                 XPathParts parts = XPathParts.getFrozenInstance(item.getFirst());
81                 if (!"id".equals(parts.getElement(-1))) {
82                     continue;
83                 }
84                 LstrType typeAttr = LstrType.fromString(parts.getAttributeValue(-1, "type"));
85                 if (typeAttr != type) {
86                     throw new IllegalArgumentException("Corrupt value for " + type);
87                 }
88                 Status subtypeAttr = Status.valueOf(parts.getAttributeValue(-1, "idStatus"));
89                 Set<String> set = submap.get(subtypeAttr);
90                 if (set == null) {
91                     submap.put(subtypeAttr, set = new LinkedHashSet<>());
92                 }
93                 for (String value : space.split(item.getSecond())) {
94                     if (type == LstrType.subdivision) {
95                         value = value.toLowerCase(Locale.ROOT).replace("-", "");
96                     }
97                     int dashPos = value.indexOf('~');
98                     if (dashPos < 0) {
99                         set.add(value);
100                     } else {
101                         StringRange.expand(value.substring(0, dashPos), value.substring(dashPos + 1), set);
102                     }
103                 }
104                 for (String code : set) {
105                     subCodeToStatus.put(code, subtypeAttr);
106                 }
107             }
108         }
109         if (data.keySet().size() < 5) {
110             throw new IllegalArgumentException("Bad directory for validity files: " + validityDir.getAbsolutePath());
111         }
112         typeToStatusToCodes = CldrUtility.protectCollectionX(data);
113         typeToCodeToStatus = CldrUtility.protectCollectionX(codeToStatus);
114     }
115 
116     /**
117      *
118      * @deprecated Use {@link #getStatusToCodes(LstrType)}
119      */
120     @Deprecated
getData()121     public Map<LstrType, Map<Status, Set<String>>> getData() {
122         return typeToStatusToCodes;
123     }
124 
getStatusToCodes(LstrType type)125     public Map<Status, Set<String>> getStatusToCodes(LstrType type) {
126         return typeToStatusToCodes.get(type);
127     }
128 
getCodeToStatus(LstrType type)129     public Map<String, Status> getCodeToStatus(LstrType type) {
130         return typeToCodeToStatus.get(type);
131     }
132 }
133