internedStrings = new ArrayList<>(stringsToIntern.size());
for (String stringToIntern : stringsToIntern) {
internedStrings.add(stringToIntern.intern());
}
return internedStrings;
}
/**
* Processes <timezones> data.
*/
private interface TimeZonesProcessor {
boolean CONTINUE = true;
boolean HALT = false;
/**
* Return {@link #CONTINUE} if processing of the XML should continue, {@link #HALT} if it
* should stop (but without considering this an error). Problems with the data are
* reported as an exception.
*
* The default implementation returns {@link #CONTINUE}.
*/
default boolean processHeader(String ianaVersion) throws XmlPullParserException {
return CONTINUE;
}
/**
* Returns {@link #CONTINUE} if processing of the XML should continue, {@link #HALT} if it
* should stop (but without considering this an error). Problems with the data are
* reported as an exception.
*
*
The default implementation returns {@link #CONTINUE}.
*/
default boolean processCountryZones(String countryIso, String defaultTimeZoneId,
boolean defaultTimeZoneBoost, boolean everUsesUtc,
List timeZoneMappings, String debugInfo)
throws XmlPullParserException {
return CONTINUE;
}
}
/**
* Validates <countryzones> elements. Intended to be used before a proposed installation
* of new data. To be valid the country ISO code must be normalized, unique, the default time
* zone ID must be one of the time zones IDs and the time zone IDs list must not be empty. The
* IDs themselves are not checked against other data to see if they are recognized because other
* classes will not have been updated with the associated new time zone data yet and so will not
* be aware of newly added IDs.
*/
private static class TimeZonesValidator implements TimeZonesProcessor {
private final Set knownCountryCodes = new HashSet<>();
@Override
public boolean processCountryZones(String countryIso, String defaultTimeZoneId,
boolean defaultTimeZoneBoost, boolean everUsesUtc,
List timeZoneMappings, String debugInfo)
throws XmlPullParserException {
if (!normalizeCountryIso(countryIso).equals(countryIso)) {
throw new XmlPullParserException("Country code: " + countryIso
+ " is not normalized at " + debugInfo);
}
if (knownCountryCodes.contains(countryIso)) {
throw new XmlPullParserException("Second entry for country code: " + countryIso
+ " at " + debugInfo);
}
if (timeZoneMappings.isEmpty()) {
throw new XmlPullParserException("No time zone IDs for country code: " + countryIso
+ " at " + debugInfo);
}
if (!TimeZoneMapping.containsTimeZoneId(timeZoneMappings, defaultTimeZoneId)) {
throw new XmlPullParserException("defaultTimeZoneId for country code: "
+ countryIso + " is not one of the zones " + timeZoneMappings + " at "
+ debugInfo);
}
knownCountryCodes.add(countryIso);
return CONTINUE;
}
}
/**
* Reads just the IANA version from the file header. The version is then available via
* {@link #getIanaVersion()}.
*/
private static class IanaVersionExtractor implements TimeZonesProcessor {
private String ianaVersion;
@Override
public boolean processHeader(String ianaVersion) throws XmlPullParserException {
this.ianaVersion = ianaVersion;
return HALT;
}
public String getIanaVersion() {
return ianaVersion;
}
}
/**
* Reads all country time zone information into memory and makes it available as a
* {@link CountryZonesFinder}.
*/
private static class CountryZonesLookupExtractor implements TimeZonesProcessor {
private List countryTimeZonesList = new ArrayList<>(250 /* default */);
@Override
public boolean processCountryZones(String countryIso, String defaultTimeZoneId,
boolean defaultTimeZoneBoost, boolean everUsesUtc,
List timeZoneMappings, String debugInfo)
throws XmlPullParserException {
CountryTimeZones countryTimeZones = CountryTimeZones
.createValidated(
countryIso, defaultTimeZoneId, defaultTimeZoneBoost, everUsesUtc,
timeZoneMappings, debugInfo);
countryTimeZonesList.add(countryTimeZones);
return CONTINUE;
}
CountryZonesFinder getCountryZonesLookup() {
return new CountryZonesFinder(countryTimeZonesList);
}
}
/**
* Extracts validated time zones information associated with a specific country code.
* Processing is halted when the country code is matched and the validated result is also made
* available via {@link #getValidatedCountryTimeZones()}.
*/
private static class SelectiveCountryTimeZonesExtractor implements TimeZonesProcessor {
private final String countryCodeToMatch;
private CountryTimeZones validatedCountryTimeZones;
private SelectiveCountryTimeZonesExtractor(String countryCodeToMatch) {
this.countryCodeToMatch = normalizeCountryIso(countryCodeToMatch);
}
@Override
public boolean processCountryZones(String countryIso, String defaultTimeZoneId,
boolean defaultTimeZoneBoost, boolean everUsesUtc,
List timeZoneMappings, String debugInfo) {
countryIso = normalizeCountryIso(countryIso);
if (!countryCodeToMatch.equals(countryIso)) {
return CONTINUE;
}
validatedCountryTimeZones = CountryTimeZones.createValidated(countryIso,
defaultTimeZoneId, defaultTimeZoneBoost, everUsesUtc, timeZoneMappings,
debugInfo);
return HALT;
}
/**
* Returns the CountryTimeZones that matched, or {@code null} if there were no matches.
*/
CountryTimeZones getValidatedCountryTimeZones() {
return validatedCountryTimeZones;
}
}
}