Home | History | Annotate | Download | only in impl
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 /*
      4  ******************************************************************************
      5  * Copyright (C) 2007-2015, International Business Machines Corporation and
      6  * others. All Rights Reserved.
      7  ******************************************************************************
      8  */
      9 
     10 package com.ibm.icu.impl.duration.impl;
     11 
     12 import java.io.BufferedReader;
     13 import java.io.IOException;
     14 import java.io.InputStream;
     15 import java.io.InputStreamReader;
     16 import java.io.UnsupportedEncodingException;
     17 import java.util.ArrayList;
     18 import java.util.Collection;
     19 import java.util.Collections;
     20 import java.util.HashMap;
     21 import java.util.List;
     22 import java.util.Map;
     23 import java.util.MissingResourceException;
     24 
     25 import com.ibm.icu.impl.ICUData;
     26 import com.ibm.icu.util.ICUUncheckedIOException;
     27 
     28 /**
     29  * A PeriodFormatterDataService that serves PeriodFormatterData objects based on
     30  * data files stored as resources in this directory. These are text files named
     31  * after the locale, for example, 'pfd_he_IL.txt' specifies an period formatter
     32  * data file for Hebrew as spoken in Israel. Data is in a JSON-like format.
     33  */
     34 public class ResourceBasedPeriodFormatterDataService extends
     35         PeriodFormatterDataService {
     36     private Collection<String> availableLocales; // of String
     37 
     38     private PeriodFormatterData lastData = null;
     39     private String lastLocale = null;
     40     private Map<String, PeriodFormatterData> cache = new HashMap<String, PeriodFormatterData>(); // String -> PeriodFormatterData
     41     // private PeriodFormatterData fallbackFormatterData;
     42 
     43     private static final String PATH = "data/";
     44 
     45     private static final ResourceBasedPeriodFormatterDataService singleton = new ResourceBasedPeriodFormatterDataService();
     46 
     47     /**
     48      * Returns the singleton instance of this class.
     49      */
     50     public static ResourceBasedPeriodFormatterDataService getInstance() {
     51         return singleton;
     52     }
     53 
     54     /**
     55      * Constructs the service.
     56      */
     57     private ResourceBasedPeriodFormatterDataService() {
     58         List<String> localeNames = new ArrayList<String>(); // of String
     59         InputStream is = ICUData.getRequiredStream(getClass(), PATH
     60                 + "index.txt");
     61         try {
     62             BufferedReader br = new BufferedReader(new InputStreamReader(is,
     63                     "UTF-8"));
     64             String string = null;
     65             while (null != (string = br.readLine())) {
     66                 string = string.trim();
     67                 if (string.startsWith("#") || string.length() == 0) {
     68                     continue;
     69                 }
     70                 localeNames.add(string);
     71             }
     72             br.close();
     73         } catch (IOException e) {
     74             throw new IllegalStateException("IO Error reading " + PATH
     75                     + "index.txt: " + e.toString());
     76         } finally {
     77             try {
     78                 is.close();
     79             } catch (IOException ignored) {
     80             }
     81         }
     82         availableLocales = Collections.unmodifiableList(localeNames);
     83     }
     84 
     85     @Override
     86     public PeriodFormatterData get(String localeName) {
     87         // remove tag info including calendar, we don't use the calendar
     88         int x = localeName.indexOf('@');
     89         if (x != -1) {
     90             localeName = localeName.substring(0, x);
     91         }
     92 
     93         synchronized (this) {
     94             if (lastLocale != null && lastLocale.equals(localeName)) {
     95                 return lastData;
     96             }
     97 
     98             PeriodFormatterData ld = cache.get(localeName);
     99             if (ld == null) {
    100                 String ln = localeName;
    101                 while (!availableLocales.contains(ln)) {
    102                     int ix = ln.lastIndexOf("_");
    103                     if (ix > -1) {
    104                         ln = ln.substring(0, ix);
    105                     } else if (!"test".equals(ln)) {
    106                         ln = "test";
    107                     } else {
    108                         ln = null;
    109                         break;
    110                     }
    111                 }
    112                 if (ln != null) {
    113                     String name = PATH + "pfd_" + ln + ".xml";
    114                     try {
    115                         InputStreamReader reader = new InputStreamReader(
    116                                 ICUData.getRequiredStream(getClass(), name), "UTF-8");
    117                         DataRecord dr = DataRecord.read(ln, new XMLRecordReader(reader));
    118                         reader.close();
    119                         if (dr != null) {
    120                             // debug
    121                             // if (false && ln.equals("ar_EG")) {
    122                             // OutputStreamWriter osw = new
    123                             // OutputStreamWriter(System.out, "UTF-8");
    124                             // XMLRecordWriter xrw = new
    125                             // XMLRecordWriter(osw);
    126                             // dr.write(xrw);
    127                             // osw.flush();
    128                             // }
    129                             ld = new PeriodFormatterData(localeName, dr);
    130                         }
    131                     } catch (UnsupportedEncodingException e) {
    132                         throw new MissingResourceException(
    133                                 "Unhandled encoding for resource " + name, name, "");
    134                     } catch (IOException e) {
    135                         throw new ICUUncheckedIOException(
    136                                 "Failed to close() resource " + name, e);
    137                     }
    138                 } else {
    139                     throw new MissingResourceException(
    140                             "Duration data not found for  " + localeName, PATH,
    141                             localeName);
    142                 }
    143 
    144                 // if (ld == null) {
    145                 // ld = getFallbackFormatterData();
    146                 // }
    147                 cache.put(localeName, ld);
    148             }
    149             lastData = ld;
    150             lastLocale = localeName;
    151 
    152             return ld;
    153         }
    154     }
    155 
    156     @Override
    157     public Collection<String> getAvailableLocales() {
    158         return availableLocales;
    159     }
    160 
    161     // PeriodFormatterData getFallbackFormatterData() {
    162     // synchronized (this) {
    163     // if (fallbackFormatterData == null) {
    164     // DataRecord dr = new DataRecord(); // hack, no default, will die if used
    165     // fallbackFormatterData = new PeriodFormatterData(null, dr);
    166     // }
    167     // return fallbackFormatterData;
    168     // }
    169     // }
    170 }
    171