/**
  * Load a properties file for a given locale. Note that locale inheritance is the responsibility
  * of the caller.
  *
  * @param prefix classpath prefix of properties file
  * @param locale locale to load
  * @return LocalizedProperties instance containing properties file or null if not found.
  */
 private LocalizedProperties getProperties(String prefix, GwtLocale locale) {
   String propFile = prefix;
   if (!locale.isDefault()) {
     propFile += "_" + locale.getAsString();
   }
   propFile += ".properties";
   InputStream str = null;
   ClassLoader classLoader = getClass().getClassLoader();
   LocalizedProperties props = new LocalizedProperties();
   try {
     str = classLoader.getResourceAsStream(propFile);
     if (str != null) {
       props.load(str, "UTF-8");
       return props;
     }
   } catch (UnsupportedEncodingException e) {
     // UTF-8 should always be defined
     return null;
   } catch (IOException e) {
     return null;
   } finally {
     if (str != null) {
       try {
         str.close();
       } catch (IOException e) {
       }
     }
   }
   return null;
 }
  /**
   * Generate an implementation class for the requested locale, including all parent classes along
   * the inheritance chain. The data will be kept at the location in the inheritance chain where it
   * was defined in properties files.
   *
   * @param logger
   * @param context
   * @param targetClass
   * @param locale
   * @return generated class name for the requested locale
   */
  private String generateLocaleTree(
      TreeLogger logger, GeneratorContext context, JClassType targetClass, GwtLocale locale) {
    String superClassName = CURRENCY_LIST;
    List<GwtLocale> searchList = locale.getCompleteSearchList();

    /** Map of currency code -> CurrencyInfo for that code. */
    Map<String, CurrencyInfo> allCurrencyData = new HashMap<String, CurrencyInfo>();

    LocalizedProperties currencyExtra = null;
    /*
     * The searchList is guaranteed to be ordered such that subclasses always
     * precede superclasses. Therefore, we iterate backwards to ensure that
     * superclasses are always generated first.
     */
    String lastDefaultCurrencyCode = null;
    for (int i = searchList.size(); i-- > 0; ) {
      GwtLocale search = searchList.get(i);
      LocalizedProperties newExtra = getProperties(CURRENCY_EXTRA_PREFIX, search);
      if (newExtra != null) {
        currencyExtra = newExtra;
      }
      Map<String, String> currencyData = getCurrencyData(search);
      Set<String> keySet = currencyData.keySet();
      String[] currencies = new String[keySet.size()];
      keySet.toArray(currencies);
      Arrays.sort(currencies);

      // Go ahead and populate the data map.
      for (String currencyCode : currencies) {
        String extraData = currencyExtra == null ? null : currencyExtra.getProperty(currencyCode);
        allCurrencyData.put(
            currencyCode,
            new CurrencyInfo(currencyCode, currencyData.get(currencyCode), extraData));
      }

      String defCurrencyCode = getDefaultCurrency(search);
      // If this locale specifies a particular locale, or the one that is
      // inherited has been changed in this locale, re-specify the default
      // currency so the method will be generated.
      if (defCurrencyCode == null && keySet.contains(lastDefaultCurrencyCode)) {
        defCurrencyCode = lastDefaultCurrencyCode;
      }
      if (!currencyData.isEmpty() || defCurrencyCode != null) {
        String newClass =
            generateOneLocale(
                logger,
                context,
                targetClass,
                search,
                superClassName,
                currencies,
                allCurrencyData,
                defCurrencyCode);
        superClassName = newClass;
        lastDefaultCurrencyCode = defCurrencyCode;
      }
    }
    return superClassName;
  }
 /**
  * Return a map of currency data for the requested locale, or null if there is not one (not that
  * inheritance is not handled here).
  *
  * <p>The keys are ISO4217 currency codes. The format of the map values is:
  *
  * <pre>
  * display name|symbol|decimal digits|not-used-flag
  * </pre>
  *
  * If a symbol is not supplied, the currency code will be used If # of decimal digits is omitted,
  * 2 is used If a currency is not generally used, not-used-flag=1 Trailing empty fields can be
  * omitted
  *
  * @param locale
  * @return currency data map
  */
 @SuppressWarnings("unchecked")
 private Map<String, String> getCurrencyData(GwtLocale locale) {
   LocalizedProperties currencyData = getProperties(CURRENCY_DATA_PREFIX, locale);
   if (currencyData == null) {
     return Collections.emptyMap();
   }
   return currencyData.getPropertyMap();
 }
 /**
  * Returns the default currency code for the requested locale.
  *
  * @param locale
  * @return ISO4217 currency code
  */
 private String getDefaultCurrency(GwtLocale locale) {
   String defCurrencyCode = null;
   LocalizedProperties numberConstants = getProperties(NUMBER_CONSTANTS_PREFIX, locale);
   if (numberConstants != null) {
     defCurrencyCode = numberConstants.getProperty("defCurrencyCode");
   }
   if (defCurrencyCode == null && locale.isDefault()) {
     defCurrencyCode = "USD";
   }
   return defCurrencyCode;
 }