Home | History | Annotate | Download | only in util
      1 package org.unicode.cldr.util;
      2 
      3 import java.util.Collections;
      4 import java.util.LinkedHashMap;
      5 import java.util.Map;
      6 import java.util.Map.Entry;
      7 
      8 import org.unicode.cldr.tool.GenerateXMB;
      9 import org.unicode.cldr.util.RegexLookup.Merger;
     10 
     11 import com.ibm.icu.text.Transform;
     12 
     13 public class PatternPlaceholders {
     14 
     15     public enum PlaceholderStatus {
     16         DISALLOWED("No placeholders allowed."), OPTIONAL("Zero or one placeholder allowed."), MULTIPLE("Zero or more placeholders allowed."), LOCALE_DEPENDENT(
     17             "Varies by locale."), REQUIRED("Placeholder required");
     18         final String message;
     19 
     20         private PlaceholderStatus(String message) {
     21             this.message = message;
     22         }
     23     }
     24 
     25     private static class PlaceholderData {
     26         PlaceholderStatus status = PlaceholderStatus.REQUIRED;
     27         Map<String, PlaceholderInfo> data = new LinkedHashMap<String, PlaceholderInfo>();
     28 
     29         public void add(String id, String name, String example) {
     30             PlaceholderInfo row = new PlaceholderInfo(name, example);
     31             data.put(id, row);
     32         }
     33     }
     34 
     35     public static class PlaceholderInfo {
     36         public String name;
     37         public String example;
     38 
     39         private PlaceholderInfo(String name, String example) {
     40             this.name = name;
     41             this.example = example;
     42         }
     43 
     44         @Override
     45         public String toString() {
     46             return name + " (" + example + ")";
     47         }
     48     }
     49 
     50     private static final class MyMerger implements Merger<PlaceholderData> {
     51         @Override
     52         public PlaceholderData merge(PlaceholderData a, PlaceholderData into) {
     53             // check unique
     54             for (String key : a.data.keySet()) {
     55                 if (into.data.containsKey(key)) {
     56                     throw new IllegalArgumentException("Duplicate placeholder: " + key);
     57                 }
     58             }
     59             into.data.putAll(a.data);
     60             if (into.status != a.status) {
     61                 throw new IllegalArgumentException("Different optional status");
     62             }
     63             return into;
     64         }
     65     }
     66 
     67     private static final class MapTransform implements Transform<String, PlaceholderData> {
     68 
     69         @Override
     70         public PlaceholderData transform(String source) {
     71             PlaceholderData result = new PlaceholderData();
     72             try {
     73                 String[] parts = source.split("\\s*;\\s+");
     74                 for (String part : parts) {
     75                     switch (part) {
     76                     case "optional":
     77                         result.status = PlaceholderStatus.OPTIONAL;
     78                         continue;
     79                     case "locale":
     80                         result.status = PlaceholderStatus.LOCALE_DEPENDENT;
     81                         continue;
     82                     case "multiple":
     83                         result.status = PlaceholderStatus.MULTIPLE;
     84                         continue;
     85                     default:
     86                         int equalsPos = part.indexOf('=');
     87                         String id = part.substring(0, equalsPos).trim();
     88                         String name = part.substring(equalsPos + 1).trim();
     89                         int spacePos = name.indexOf(' ');
     90                         String example;
     91                         if (spacePos >= 0) {
     92                             example = name.substring(spacePos + 1).trim();
     93                             name = name.substring(0, spacePos).trim();
     94                         } else {
     95                             example = "";
     96                         }
     97 
     98                         PlaceholderInfo old = result.data.get(id);
     99                         if (old != null) {
    100                             throw new IllegalArgumentException("Key occurs twice: " + id + "=" + old + "!=" + name);
    101                         }
    102                         result.add(id, name, example);
    103                     }
    104                 }
    105             } catch (Exception e) {
    106                 throw new IllegalArgumentException("Failed to parse " + source, e);
    107             }
    108             for (Entry<String, PlaceholderInfo> entry : result.data.entrySet()) {
    109                 if (GenerateXMB.DEBUG) System.out.println(entry);
    110             }
    111             return result;
    112         }
    113 
    114     }
    115 
    116     private RegexLookup<PlaceholderData> patternPlaceholders;
    117 
    118     private static PatternPlaceholders SINGLETON;
    119 
    120     private PatternPlaceholders() {
    121     }
    122 
    123     public static PatternPlaceholders getInstance() {
    124         if (SINGLETON == null) {
    125             SINGLETON = new PatternPlaceholders();
    126             SINGLETON.patternPlaceholders = RegexLookup.of(new MapTransform())
    127                 .setValueMerger(new MyMerger())
    128                 .loadFromFile(PatternPlaceholders.class, "data/Placeholders.txt");
    129         }
    130         return SINGLETON;
    131     }
    132 
    133     public Map<String, PlaceholderInfo> get(String path) {
    134         // TODO change the original map to be unmodifiable, to avoid this step. Need to add a "finalize" to the lookup.
    135         final PlaceholderData map = patternPlaceholders.get(path);
    136         return map == null ? null : Collections.unmodifiableMap(map.data);
    137     }
    138 
    139     public PlaceholderStatus getStatus(String path) {
    140         // TODO change the original map to be unmodifiable, to avoid this step. Need to add a "finalize" to the lookup.
    141         final PlaceholderData map = patternPlaceholders.get(path);
    142         return map == null ? PlaceholderStatus.DISALLOWED : map.status;
    143     }
    144 }