• 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, 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