private void setup(
      String resourceKey,
      Map<TimeUnit, Map<String, Object[]>> timeUnitToCountToPatterns,
      int style) {
    // fill timeUnitToCountToPatterns from resource file
    try {
      ICUResourceBundle resource =
          (ICUResourceBundle)
              UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale);
      ICUResourceBundle unitsRes = resource.getWithFallback(resourceKey);
      int size = unitsRes.getSize();
      for (int index = 0; index < size; ++index) {
        String timeUnitName = unitsRes.get(index).getKey();
        TimeUnit timeUnit = null;
        if (timeUnitName.equals("year")) {
          timeUnit = TimeUnit.YEAR;
        } else if (timeUnitName.equals("month")) {
          timeUnit = TimeUnit.MONTH;
        } else if (timeUnitName.equals("day")) {
          timeUnit = TimeUnit.DAY;
        } else if (timeUnitName.equals("hour")) {
          timeUnit = TimeUnit.HOUR;
        } else if (timeUnitName.equals("minute")) {
          timeUnit = TimeUnit.MINUTE;
        } else if (timeUnitName.equals("second")) {
          timeUnit = TimeUnit.SECOND;
        } else if (timeUnitName.equals("week")) {
          timeUnit = TimeUnit.WEEK;
        } else {
          continue;
        }
        ICUResourceBundle oneUnitRes = unitsRes.getWithFallback(timeUnitName);
        int count = oneUnitRes.getSize();
        Map<String, Object[]> countToPatterns = timeUnitToCountToPatterns.get(timeUnit);
        if (countToPatterns == null) {
          countToPatterns = new TreeMap<String, Object[]>();
          timeUnitToCountToPatterns.put(timeUnit, countToPatterns);
        }
        for (int pluralIndex = 0; pluralIndex < count; ++pluralIndex) {
          String pluralCount = oneUnitRes.get(pluralIndex).getKey();
          String pattern = oneUnitRes.get(pluralIndex).getString();
          final MessageFormat messageFormat = new MessageFormat(pattern, locale);
          if (format != null) {
            messageFormat.setFormatByArgumentIndex(0, format);
          }
          // save both full name and abbreviated name in one table
          // is good space-wise, but it degrades performance,
          // since it needs to check whether the needed space
          // is already allocated or not.
          Object[] pair = countToPatterns.get(pluralCount);
          if (pair == null) {
            pair = new Object[2];
            countToPatterns.put(pluralCount, pair);
          }
          pair[style] = messageFormat;
        }
      }
    } catch (MissingResourceException e) {
    }

    // there should be patterns for each plural rule in each time unit.
    // For each time unit,
    //     for each plural rule, following is unit pattern fall-back rule:
    //         ( for example: "one" hour )
    //         look for its unit pattern in its locale tree.
    //         if pattern is not found in its own locale, such as de_DE,
    //         look for the pattern in its parent, such as de,
    //         keep looking till found or till root.
    //         if the pattern is not found in root either,
    //         fallback to plural count "other",
    //         look for the pattern of "other" in the locale tree:
    //         "de_DE" to "de" to "root".
    //         If not found, fall back to value of
    //         static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h".
    //
    // Following is consistency check to create pattern for each
    // plural rule in each time unit using above fall-back rule.
    //
    final TimeUnit[] timeUnits = TimeUnit.values();
    Set<String> keywords = pluralRules.getKeywords();
    for (int i = 0; i < timeUnits.length; ++i) {
      // for each time unit,
      // get all the patterns for each plural rule in this locale.
      final TimeUnit timeUnit = timeUnits[i];
      Map<String, Object[]> countToPatterns = timeUnitToCountToPatterns.get(timeUnit);
      if (countToPatterns == null) {
        countToPatterns = new TreeMap<String, Object[]>();
        timeUnitToCountToPatterns.put(timeUnit, countToPatterns);
      }
      for (String pluralCount : keywords) {
        if (countToPatterns.get(pluralCount) == null
            || countToPatterns.get(pluralCount)[style] == null) {
          // look through parents
          searchInTree(resourceKey, style, timeUnit, pluralCount, pluralCount, countToPatterns);
        }
      }
    }
  }
  // srcPluralCount is the original plural count on which the pattern is
  // searched for.
  // searchPluralCount is the fallback plural count.
  // For example, to search for pattern for ""one" hour",
  // "one" is the srcPluralCount,
  // if the pattern is not found even in root, fallback to
  // using patterns of plural count "other",
  // then, "other" is the searchPluralCount.
  private void searchInTree(
      String resourceKey,
      int styl,
      TimeUnit timeUnit,
      String srcPluralCount,
      String searchPluralCount,
      Map<String, Object[]> countToPatterns) {
    ULocale parentLocale = locale;
    String srcTimeUnitName = timeUnit.toString();
    while (parentLocale != null) {
      try {
        // look for pattern for srcPluralCount in locale tree
        ICUResourceBundle unitsRes =
            (ICUResourceBundle)
                UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, parentLocale);
        unitsRes = unitsRes.getWithFallback(resourceKey);
        ICUResourceBundle oneUnitRes = unitsRes.getWithFallback(srcTimeUnitName);
        String pattern = oneUnitRes.getStringWithFallback(searchPluralCount);
        final MessageFormat messageFormat = new MessageFormat(pattern, locale);
        if (format != null) {
          messageFormat.setFormatByArgumentIndex(0, format);
        }
        Object[] pair = countToPatterns.get(srcPluralCount);
        if (pair == null) {
          pair = new Object[2];
          countToPatterns.put(srcPluralCount, pair);
        }
        pair[styl] = messageFormat;
        return;
      } catch (MissingResourceException e) {
      }
      parentLocale = parentLocale.getFallback();
    }

    // if no unitsShort resource was found even after fallback to root locale
    // then search the units resource fallback from the current level to root
    if (parentLocale == null && resourceKey.equals("unitsShort")) {
      searchInTree("units", styl, timeUnit, srcPluralCount, searchPluralCount, countToPatterns);
      if (countToPatterns != null
          && countToPatterns.get(srcPluralCount) != null
          && countToPatterns.get(srcPluralCount)[styl] != null) {
        return;
      }
    }

    // if not found the pattern for this plural count at all,
    // fall-back to plural count "other"
    if (searchPluralCount.equals("other")) {
      // set default fall back the same as the resource in root
      MessageFormat messageFormat = null;
      if (timeUnit == TimeUnit.SECOND) {
        messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_SECOND, locale);
      } else if (timeUnit == TimeUnit.MINUTE) {
        messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MINUTE, locale);
      } else if (timeUnit == TimeUnit.HOUR) {
        messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_HOUR, locale);
      } else if (timeUnit == TimeUnit.WEEK) {
        messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_WEEK, locale);
      } else if (timeUnit == TimeUnit.DAY) {
        messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_DAY, locale);
      } else if (timeUnit == TimeUnit.MONTH) {
        messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_MONTH, locale);
      } else if (timeUnit == TimeUnit.YEAR) {
        messageFormat = new MessageFormat(DEFAULT_PATTERN_FOR_YEAR, locale);
      }
      if (format != null && messageFormat != null) {
        messageFormat.setFormatByArgumentIndex(0, format);
      }
      Object[] pair = countToPatterns.get(srcPluralCount);
      if (pair == null) {
        pair = new Object[2];
        countToPatterns.put(srcPluralCount, pair);
      }
      pair[styl] = messageFormat;
    } else {
      // fall back to rule "other", and search in parents
      searchInTree(resourceKey, styl, timeUnit, srcPluralCount, "other", countToPatterns);
    }
  }
  /*
   * Initialize DateIntervalInfo from calendar data
   * @param calData  calendar data
   */
  private void setup(ULocale locale) {
    int DEFAULT_HASH_SIZE = 19;
    fIntervalPatterns = new HashMap<String, Map<String, PatternInfo>>(DEFAULT_HASH_SIZE);
    // initialize to guard if there is no interval date format defined in
    // resource files
    fFallbackIntervalPattern = "{0} \u2013 {1}";
    HashSet<String> skeletonSet = new HashSet<String>();
    try {
      // loop through all locales to get all available skeletons'
      // interval format
      ULocale currentLocale = locale;
      // Get the correct calendar type
      String calendarTypeToUse = locale.getKeywordValue("calendar");
      if (calendarTypeToUse == null) {
        String[] preferredCalendarTypes =
            Calendar.getKeywordValuesForLocale("calendar", locale, true);
        calendarTypeToUse = preferredCalendarTypes[0]; // the most preferred calendar
      }
      if (calendarTypeToUse == null) {
        calendarTypeToUse = "gregorian"; // fallback
      }
      do {
        String name = currentLocale.getName();
        if (name.length() == 0) {
          break;
        }

        ICUResourceBundle rb =
            (ICUResourceBundle)
                UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, currentLocale);
        // Note:
        //      ICU4J getWithFallback does not work well when
        //      1) A nested table is an alias to /LOCALE/...
        //      2) getWithFallback is called multiple times for going down hierarchical resource
        // path
        //      #9987 resolved the issue of alias table when full path is specified in
        // getWithFallback,
        //      but there is no easy solution when the equivalent operation is done by multiple
        // operations.
        //      This issue is addressed in #9964.
        //                ICUResourceBundle calBundle = rb.getWithFallback("calendar");
        //                ICUResourceBundle calTypeBundle =
        // calBundle.getWithFallback(calendarTypeToUse);
        ICUResourceBundle itvDtPtnResource =
            rb.getWithFallback("calendar/" + calendarTypeToUse + "/intervalFormats");
        // look for fallback first, since it establishes the default order
        String fallback = itvDtPtnResource.getStringWithFallback(FALLBACK_STRING);
        setFallbackIntervalPattern(fallback);
        int size = itvDtPtnResource.getSize();
        for (int index = 0; index < size; ++index) {
          String skeleton = itvDtPtnResource.get(index).getKey();
          if (skeletonSet.contains(skeleton)) {
            continue;
          }
          skeletonSet.add(skeleton);
          if (skeleton.compareTo(FALLBACK_STRING) == 0) {
            continue;
          }
          ICUResourceBundle intervalPatterns = (ICUResourceBundle) itvDtPtnResource.get(skeleton);
          int ptnNum = intervalPatterns.getSize();
          for (int ptnIndex = 0; ptnIndex < ptnNum; ++ptnIndex) {
            String key = intervalPatterns.get(ptnIndex).getKey();
            String pattern = intervalPatterns.get(ptnIndex).getString();

            int calendarField = -1; // initialize with an invalid value.
            if (key.compareTo(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.YEAR]) == 0) {
              calendarField = Calendar.YEAR;
            } else if (key.compareTo(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.MONTH]) == 0) {
              calendarField = Calendar.MONTH;
            } else if (key.compareTo(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.DATE]) == 0) {
              calendarField = Calendar.DATE;
            } else if (key.compareTo(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.AM_PM]) == 0) {
              calendarField = Calendar.AM_PM;
            } else if (key.compareTo(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.HOUR]) == 0) {
              calendarField = Calendar.HOUR;
            } else if (key.compareTo(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.MINUTE]) == 0) {
              calendarField = Calendar.MINUTE;
            }

            if (calendarField != -1) {
              setIntervalPatternInternally(skeleton, key, pattern);
            }
          }
        }
        try {
          UResourceBundle parentNameBundle = rb.get("%%Parent");
          currentLocale = new ULocale(parentNameBundle.getString());
        } catch (MissingResourceException e) {
          currentLocale = currentLocale.getFallback();
        }
      } while (currentLocale != null && !currentLocale.getBaseName().equals("root"));
    } catch (MissingResourceException e) {
      // ok, will fallback to {data0} - {date1}
    }
  }