OpenJDK / loom / loom
changeset 48292:191ae61bd1e9
Merge
author | prr |
---|---|
date | Wed, 13 Dec 2017 10:25:38 -0800 |
parents | 093027a037cf a559b7cd1dea |
children | 2fa0077c4fec 1f38b6c89f8a |
files | src/java.base/share/classes/java/lang/StringDecoderUTF8.java src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java test/java/util/Calendar/Bug8185841.java test/jdk/TEST.groups test/langtools/jdk/javadoc/doclet/testMemberInheritence/TestMemberInheritence.java test/langtools/jdk/javadoc/doclet/testMemberInheritence/diamond/A.java test/langtools/jdk/javadoc/doclet/testMemberInheritence/diamond/B.java test/langtools/jdk/javadoc/doclet/testMemberInheritence/diamond/C.java test/langtools/jdk/javadoc/doclet/testMemberInheritence/diamond/X.java test/langtools/jdk/javadoc/doclet/testMemberInheritence/diamond/Z.java test/langtools/jdk/javadoc/doclet/testMemberInheritence/inheritDist/A.java test/langtools/jdk/javadoc/doclet/testMemberInheritence/inheritDist/B.java test/langtools/jdk/javadoc/doclet/testMemberInheritence/inheritDist/C.java test/langtools/jdk/javadoc/doclet/testMemberInheritence/pkg/BaseClass.java test/langtools/jdk/javadoc/doclet/testMemberInheritence/pkg/BaseInterface.java test/langtools/jdk/javadoc/doclet/testMemberInheritence/pkg/SubClass.java test/langtools/jdk/javadoc/doclet/testMemberInheritence/pkg1/Implementer.java test/langtools/jdk/javadoc/doclet/testMemberInheritence/pkg1/Interface.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/TestBadOverride.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/TestMultiInheritence.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/TestOverrideMethods.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/TestOverridenMethodDocCopy.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/TestOverridenPrivateMethods.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/TestOverridenPrivateMethodsWithPackageFlag.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/TestOverridenPrivateMethodsWithPrivateFlag.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/pkg1/BaseClass.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/pkg1/SubClass.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/pkg2/SubClass.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/pkg3/I0.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/pkg3/I1.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/pkg3/I2.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/pkg3/I3.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/pkg3/I4.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/pkg4/Foo.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/pkg5/Classes.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/pkg5/Interfaces.java test/langtools/jdk/javadoc/doclet/testOverridenMethods/pkg5/TestEnum.java test/langtools/jdk/jshell/ToolSimpleTest.java |
diffstat | 247 files changed, 13229 insertions(+), 4510 deletions(-) [+] |
line wrap: on
line diff
--- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java Wed Dec 13 13:27:45 2017 +0530 +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java Wed Dec 13 10:25:38 2017 -0800 @@ -37,6 +37,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; +import java.util.stream.IntStream; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.SAXNotRecognizedException; @@ -52,21 +53,32 @@ static final String LDML_DTD_SYSTEM_ID = "http://www.unicode.org/cldr/dtd/2.0/ldml.dtd"; static final String SPPL_LDML_DTD_SYSTEM_ID = "http://www.unicode.org/cldr/dtd/2.0/ldmlSupplemental.dtd"; + static final String BCP47_LDML_DTD_SYSTEM_ID = "http://www.unicode.org/cldr/dtd/2.0/ldmlBCP47.dtd"; + private static String CLDR_BASE = "../CLDR/21.0.1/"; static String LOCAL_LDML_DTD; static String LOCAL_SPPL_LDML_DTD; + static String LOCAL_BCP47_LDML_DTD; private static String SOURCE_FILE_DIR; private static String SPPL_SOURCE_FILE; private static String NUMBERING_SOURCE_FILE; private static String METAZONES_SOURCE_FILE; private static String LIKELYSUBTAGS_SOURCE_FILE; + private static String TIMEZONE_SOURCE_FILE; static String DESTINATION_DIR = "build/gensrc"; static final String LOCALE_NAME_PREFIX = "locale.displayname."; + static final String LOCALE_SEPARATOR = LOCALE_NAME_PREFIX + "separator"; + static final String LOCALE_KEYTYPE = LOCALE_NAME_PREFIX + "keytype"; + static final String LOCALE_KEY_PREFIX = LOCALE_NAME_PREFIX + "key."; + static final String LOCALE_TYPE_PREFIX = LOCALE_NAME_PREFIX + "type."; + static final String LOCALE_TYPE_PREFIX_CA = LOCALE_TYPE_PREFIX + "ca."; static final String CURRENCY_SYMBOL_PREFIX = "currency.symbol."; static final String CURRENCY_NAME_PREFIX = "currency.displayname."; static final String CALENDAR_NAME_PREFIX = "calendarname."; + static final String CALENDAR_FIRSTDAY_PREFIX = "firstDay."; + static final String CALENDAR_MINDAYS_PREFIX = "minDays."; static final String TIMEZONE_ID_PREFIX = "timezone.id."; static final String ZONE_NAME_PREFIX = "timezone.displayname."; static final String METAZONE_ID_PREFIX = "metazone.id."; @@ -76,6 +88,7 @@ private static LikelySubtagsParseHandler handlerLikelySubtags; static NumberingSystemsParseHandler handlerNumbering; static MetaZonesParseHandler handlerMetaZones; + static TimeZoneParseHandler handlerTimeZone; private static BundleGenerator bundleGenerator; // java.base module related @@ -201,11 +214,13 @@ // Set up path names LOCAL_LDML_DTD = CLDR_BASE + "/dtd/ldml.dtd"; LOCAL_SPPL_LDML_DTD = CLDR_BASE + "/dtd/ldmlSupplemental.dtd"; + LOCAL_BCP47_LDML_DTD = CLDR_BASE + "/dtd/ldmlBCP47.dtd"; SOURCE_FILE_DIR = CLDR_BASE + "/main"; SPPL_SOURCE_FILE = CLDR_BASE + "/supplemental/supplementalData.xml"; LIKELYSUBTAGS_SOURCE_FILE = CLDR_BASE + "/supplemental/likelySubtags.xml"; NUMBERING_SOURCE_FILE = CLDR_BASE + "/supplemental/numberingSystems.xml"; METAZONES_SOURCE_FILE = CLDR_BASE + "/supplemental/metaZones.xml"; + TIMEZONE_SOURCE_FILE = CLDR_BASE + "/bcp47/timezone.xml"; if (BASE_LOCALES.isEmpty()) { setupBaseLocales("en-US"); @@ -215,10 +230,10 @@ // Parse data independent of locales parseSupplemental(); + parseBCP47(); List<Bundle> bundles = readBundleList(); convertBundles(bundles); - convertBundles(addedBundles); } private static void usage() { @@ -314,34 +329,19 @@ } private static final Map<String, Map<String, Object>> cldrBundles = new HashMap<>(); - // this list will contain additional bundles to be generated for Region dependent Data. - private static List<Bundle> addedBundles = new ArrayList<>(); private static Map<String, SortedSet<String>> metaInfo = new HashMap<>(); static { // For generating information on supported locales. - metaInfo.put("LocaleNames", new TreeSet<>()); - metaInfo.put("CurrencyNames", new TreeSet<>()); - metaInfo.put("TimeZoneNames", new TreeSet<>()); - metaInfo.put("CalendarData", new TreeSet<>()); - metaInfo.put("FormatData", new TreeSet<>()); metaInfo.put("AvailableLocales", new TreeSet<>()); } - - private static Set<String> calendarDataFields = Set.of("firstDayOfWeek", "minimalDaysInFirstWeek"); - static Map<String, Object> getCLDRBundle(String id) throws Exception { Map<String, Object> bundle = cldrBundles.get(id); if (bundle != null) { return bundle; } - SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setValidating(true); - SAXParser parser = factory.newSAXParser(); - enableFileAccess(parser); - LDMLParseHandler handler = new LDMLParseHandler(id); File file = new File(SOURCE_FILE_DIR + File.separator + id + ".xml"); if (!file.exists()) { // Skip if the file doesn't exist. @@ -349,14 +349,15 @@ } info("..... main directory ....."); - info("Reading file " + file); - parser.parse(file, handler); + LDMLParseHandler handler = new LDMLParseHandler(id); + parseLDMLFile(file, handler); bundle = handler.getData(); cldrBundles.put(id, bundle); - String country = getCountryCode(id); - if (country != null) { - bundle = handlerSuppl.getData(country); + + if (id.equals("root")) { + // Calendar data (firstDayOfWeek & minDaysInFirstWeek) + bundle = handlerSuppl.getData("root"); if (bundle != null) { //merge two maps into one map Map<String, Object> temp = cldrBundles.remove(id); @@ -379,98 +380,44 @@ // SupplementalData file also provides the "parent" locales which // are othrwise not to be fallen back. Process them here as well. // - info("..... Parsing supplementalData.xml ....."); - SAXParserFactory factorySuppl = SAXParserFactory.newInstance(); - factorySuppl.setValidating(true); - SAXParser parserSuppl = factorySuppl.newSAXParser(); - enableFileAccess(parserSuppl); handlerSuppl = new SupplementDataParseHandler(); - File fileSupply = new File(SPPL_SOURCE_FILE); - parserSuppl.parse(fileSupply, handlerSuppl); + parseLDMLFile(new File(SPPL_SOURCE_FILE), handlerSuppl); Map<String, Object> parentData = handlerSuppl.getData("root"); - parentData.keySet().forEach(key -> { + parentData.keySet().stream() + .filter(key -> key.startsWith(PARENT_LOCALE_PREFIX)) + .forEach(key -> { parentLocalesMap.put(key, new TreeSet( Arrays.asList(((String)parentData.get(key)).split(" ")))); }); // Parse numberingSystems to get digit zero character information. - SAXParserFactory numberingParser = SAXParserFactory.newInstance(); - numberingParser.setValidating(true); - SAXParser parserNumbering = numberingParser.newSAXParser(); - enableFileAccess(parserNumbering); handlerNumbering = new NumberingSystemsParseHandler(); - File fileNumbering = new File(NUMBERING_SOURCE_FILE); - parserNumbering.parse(fileNumbering, handlerNumbering); + parseLDMLFile(new File(NUMBERING_SOURCE_FILE), handlerNumbering); // Parse metaZones to create mappings between Olson tzids and CLDR meta zone names - info("..... Parsing metaZones.xml ....."); - SAXParserFactory metazonesParser = SAXParserFactory.newInstance(); - metazonesParser.setValidating(true); - SAXParser parserMetaZones = metazonesParser.newSAXParser(); - enableFileAccess(parserMetaZones); handlerMetaZones = new MetaZonesParseHandler(); - File fileMetaZones = new File(METAZONES_SOURCE_FILE); - parserMetaZones.parse(fileMetaZones, handlerMetaZones); + parseLDMLFile(new File(METAZONES_SOURCE_FILE), handlerMetaZones); // Parse likelySubtags - info("..... Parsing likelySubtags.xml ....."); - SAXParserFactory likelySubtagsParser = SAXParserFactory.newInstance(); - likelySubtagsParser.setValidating(true); - SAXParser parserLikelySubtags = likelySubtagsParser.newSAXParser(); - enableFileAccess(parserLikelySubtags); handlerLikelySubtags = new LikelySubtagsParseHandler(); - File fileLikelySubtags = new File(LIKELYSUBTAGS_SOURCE_FILE); - parserLikelySubtags.parse(fileLikelySubtags, handlerLikelySubtags); + parseLDMLFile(new File(LIKELYSUBTAGS_SOURCE_FILE), handlerLikelySubtags); } - /** - * This method will check if a new region dependent Bundle needs to be - * generated for this Locale id and targetMap. New Bundle will be generated - * when Locale id has non empty script and country code and targetMap - * contains region dependent data. This method will also remove region - * dependent data from this targetMap after candidate locales check. E.g. It - * will call genRegionDependentBundle() in case of az_Latn_AZ locale and - * remove region dependent data from this targetMap so that az_Latn_AZ - * bundle will not be created. For az_Cyrl_AZ, new Bundle will be generated - * but region dependent data will not be removed from targetMap as its candidate - * locales are [az_Cyrl_AZ, az_Cyrl, root], which does not include az_AZ for - * fallback. - * - */ + // Parsers for data in "bcp47" directory + // + private static void parseBCP47() throws Exception { + // Parse timezone + handlerTimeZone = new TimeZoneParseHandler(); + parseLDMLFile(new File(TIMEZONE_SOURCE_FILE), handlerTimeZone); + } - private static void checkRegionDependentBundle(Map<String, Object> targetMap, String id) { - if ((CLDRConverter.getScript(id) != "") - && (CLDRConverter.getCountryCode(id) != "")) { - Map<String, Object> regionDepDataMap = targetMap - .keySet() - .stream() - .filter(calendarDataFields::contains) - .collect(Collectors.toMap(k -> k, targetMap::get)); - if (!regionDepDataMap.isEmpty()) { - Locale cldrLoc = new Locale(CLDRConverter.getLanguageCode(id), - CLDRConverter.getCountryCode(id)); - genRegionDependentBundle(regionDepDataMap, cldrLoc); - if (checkCandidateLocales(id, cldrLoc)) { - // Remove matchedKeys from this targetMap only if checkCandidateLocales() returns true. - regionDepDataMap.keySet().forEach(targetMap::remove); - } - } - } - } - /** - * This method will generate a new Bundle for region dependent data, - * minimalDaysInFirstWeek and firstDayOfWeek. Newly generated Bundle will be added - * to addedBundles list. - */ - private static void genRegionDependentBundle(Map<String, Object> targetMap, Locale cldrLoc) { - String localeId = cldrLoc.toString(); - StringBuilder sb = getCandLocales(cldrLoc); - if (sb.indexOf(localeId) == -1) { - sb.append(localeId); - } - Bundle bundle = new Bundle(localeId, sb.toString(), null, null); - cldrBundles.put(localeId, targetMap); - addedBundles.add(bundle); + private static void parseLDMLFile(File srcfile, AbstractLDMLHandler handler) throws Exception { + info("..... Parsing " + srcfile.getName() + " ....."); + SAXParserFactory pf = SAXParserFactory.newInstance(); + pf.setValidating(true); + SAXParser parser = pf.newSAXParser(); + enableFileAccess(parser); + parser.parse(srcfile, handler); } private static StringBuilder getCandLocales(Locale cldrLoc) { @@ -491,16 +438,6 @@ return candList; } - /** - * This method will return true, if for a given locale, its language and - * country specific locale will exist in runtime lookup path. E.g. it will - * return true for bs_Latn_BA. - */ - private static boolean checkCandidateLocales(String id, Locale cldrLoc) { - return(getCandidateLocales(Locale.forLanguageTag(id.replaceAll("_", "-"))) - .contains(cldrLoc)); - } - private static void convertBundles(List<Bundle> bundles) throws Exception { // parent locales map. The mappings are put in base metaInfo file // for now. @@ -514,8 +451,6 @@ Map<String, Object> targetMap = bundle.getTargetMap(); - // check if new region DependentBundle needs to be generated for this Locale. - checkRegionDependentBundle(targetMap, bundle.getID()); EnumSet<Bundle.Type> bundleTypes = bundle.getBundleTypes(); if (bundle.isRoot()) { @@ -528,40 +463,30 @@ if (bundleTypes.contains(Bundle.Type.LOCALENAMES)) { Map<String, Object> localeNamesMap = extractLocaleNames(targetMap, bundle.getID()); if (!localeNamesMap.isEmpty() || bundle.isRoot()) { - metaInfo.get("LocaleNames").add(toLanguageTag(bundle.getID())); - addLikelySubtags(metaInfo, "LocaleNames", bundle.getID()); bundleGenerator.generateBundle("util", "LocaleNames", bundle.getJavaID(), true, localeNamesMap, BundleType.OPEN); } } if (bundleTypes.contains(Bundle.Type.CURRENCYNAMES)) { Map<String, Object> currencyNamesMap = extractCurrencyNames(targetMap, bundle.getID(), bundle.getCurrencies()); if (!currencyNamesMap.isEmpty() || bundle.isRoot()) { - metaInfo.get("CurrencyNames").add(toLanguageTag(bundle.getID())); - addLikelySubtags(metaInfo, "CurrencyNames", bundle.getID()); bundleGenerator.generateBundle("util", "CurrencyNames", bundle.getJavaID(), true, currencyNamesMap, BundleType.OPEN); } } if (bundleTypes.contains(Bundle.Type.TIMEZONENAMES)) { Map<String, Object> zoneNamesMap = extractZoneNames(targetMap, bundle.getID()); if (!zoneNamesMap.isEmpty() || bundle.isRoot()) { - metaInfo.get("TimeZoneNames").add(toLanguageTag(bundle.getID())); - addLikelySubtags(metaInfo, "TimeZoneNames", bundle.getID()); bundleGenerator.generateBundle("util", "TimeZoneNames", bundle.getJavaID(), true, zoneNamesMap, BundleType.TIMEZONE); } } if (bundleTypes.contains(Bundle.Type.CALENDARDATA)) { Map<String, Object> calendarDataMap = extractCalendarData(targetMap, bundle.getID()); if (!calendarDataMap.isEmpty() || bundle.isRoot()) { - metaInfo.get("CalendarData").add(toLanguageTag(bundle.getID())); - addLikelySubtags(metaInfo, "CalendarData", bundle.getID()); bundleGenerator.generateBundle("util", "CalendarData", bundle.getJavaID(), true, calendarDataMap, BundleType.PLAIN); } } if (bundleTypes.contains(Bundle.Type.FORMATDATA)) { Map<String, Object> formatDataMap = extractFormatData(targetMap, bundle.getID()); if (!formatDataMap.isEmpty() || bundle.isRoot()) { - metaInfo.get("FormatData").add(toLanguageTag(bundle.getID())); - addLikelySubtags(metaInfo, "FormatData", bundle.getID()); bundleGenerator.generateBundle("text", "FormatData", bundle.getJavaID(), true, formatDataMap, BundleType.PLAIN); } } @@ -570,43 +495,9 @@ metaInfo.get("AvailableLocales").add(toLanguageTag(bundle.getID())); addLikelySubtags(metaInfo, "AvailableLocales", bundle.getID()); } - addCldrImplicitLocales(metaInfo); bundleGenerator.generateMetaInfo(metaInfo); } - /** - * These are the Locales that are implicitly supported by CLDR. - * Adding them explicitly as likelySubtags here, will ensure that - * COMPAT locales do not precede them during ResourceBundle search path. - */ - private static void addCldrImplicitLocales(Map<String, SortedSet<String>> metaInfo) { - metaInfo.get("LocaleNames").add("zh-Hans-CN"); - metaInfo.get("LocaleNames").add("zh-Hans-SG"); - metaInfo.get("LocaleNames").add("zh-Hant-HK"); - metaInfo.get("LocaleNames").add("zh-Hant-MO"); - metaInfo.get("LocaleNames").add("zh-Hant-TW"); - metaInfo.get("CurrencyNames").add("zh-Hans-CN"); - metaInfo.get("CurrencyNames").add("zh-Hans-SG"); - metaInfo.get("CurrencyNames").add("zh-Hant-HK"); - metaInfo.get("CurrencyNames").add("zh-Hant-MO"); - metaInfo.get("CurrencyNames").add("zh-Hant-TW"); - metaInfo.get("TimeZoneNames").add("zh-Hans-CN"); - metaInfo.get("TimeZoneNames").add("zh-Hans-SG"); - metaInfo.get("TimeZoneNames").add("zh-Hant-HK"); - metaInfo.get("TimeZoneNames").add("zh-Hant-MO"); - metaInfo.get("TimeZoneNames").add("zh-Hant-TW"); - metaInfo.get("TimeZoneNames").add("zh-HK"); - metaInfo.get("CalendarData").add("zh-Hans-CN"); - metaInfo.get("CalendarData").add("zh-Hans-SG"); - metaInfo.get("CalendarData").add("zh-Hant-HK"); - metaInfo.get("CalendarData").add("zh-Hant-MO"); - metaInfo.get("CalendarData").add("zh-Hant-TW"); - metaInfo.get("FormatData").add("zh-Hans-CN"); - metaInfo.get("FormatData").add("zh-Hans-SG"); - metaInfo.get("FormatData").add("zh-Hant-HK"); - metaInfo.get("FormatData").add("zh-Hant-MO"); - metaInfo.get("FormatData").add("zh-Hant-TW"); - } static final Map<String, String> aliases = new HashMap<>(); /** @@ -656,14 +547,6 @@ return Locale.forLanguageTag(id.replaceAll("_", "-")).getCountry(); } - /* - * Returns the script portion of the given id. - * If id is "root", "" is returned. - */ - static String getScript(String id) { - return "root".equals(id) ? "" : Locale.forLanguageTag(id.replaceAll("_", "-")).getScript(); - } - private static class KeyComparator implements Comparator<String> { static KeyComparator INSTANCE = new KeyComparator(); @@ -695,9 +578,25 @@ Map<String, Object> localeNames = new TreeMap<>(KeyComparator.INSTANCE); for (String key : map.keySet()) { if (key.startsWith(LOCALE_NAME_PREFIX)) { - localeNames.put(key.substring(LOCALE_NAME_PREFIX.length()), map.get(key)); + switch (key) { + case LOCALE_SEPARATOR: + localeNames.put("ListCompositionPattern", map.get(key)); + break; + case LOCALE_KEYTYPE: + localeNames.put("ListKeyTypePattern", map.get(key)); + break; + default: + localeNames.put(key.substring(LOCALE_NAME_PREFIX.length()), map.get(key)); + break; + } } } + + if (id.equals("root")) { + // Add display name pattern, which is not in CLDR + localeNames.put("DisplayNamePattern", "{0,choice,0#|1#{1}|2#{1} ({2})}"); + } + return localeNames; } @@ -778,10 +677,30 @@ return names; } + /** + * Extracts the language independent calendar data. Each of the two keys, + * "firstDayOfWeek" and "minimalDaysInFirstWeek" has a string value consists of + * one or multiple occurrences of: + * i: rg1 rg2 ... rgn; + * where "i" is the data for the following regions (delimited by a space) after + * ":", and ends with a ";". + */ private static Map<String, Object> extractCalendarData(Map<String, Object> map, String id) { Map<String, Object> calendarData = new LinkedHashMap<>(); - copyIfPresent(map, "firstDayOfWeek", calendarData); - copyIfPresent(map, "minimalDaysInFirstWeek", calendarData); + if (id.equals("root")) { + calendarData.put("firstDayOfWeek", + IntStream.range(1, 8) + .mapToObj(String::valueOf) + .filter(d -> map.keySet().contains(CALENDAR_FIRSTDAY_PREFIX + d)) + .map(d -> d + ": " + map.get(CALENDAR_FIRSTDAY_PREFIX + d)) + .collect(Collectors.joining(";"))); + calendarData.put("minimalDaysInFirstWeek", + IntStream.range(0, 7) + .mapToObj(String::valueOf) + .filter(d -> map.keySet().contains(CALENDAR_MINDAYS_PREFIX + d)) + .map(d -> d + ": " + map.get(CALENDAR_MINDAYS_PREFIX + d)) + .collect(Collectors.joining(";"))); + } return calendarData; } @@ -844,17 +763,19 @@ for (String key : map.keySet()) { // Copy available calendar names - if (key.startsWith(CLDRConverter.CALENDAR_NAME_PREFIX)) { - String type = key.substring(CLDRConverter.CALENDAR_NAME_PREFIX.length()); + if (key.startsWith(CLDRConverter.LOCALE_TYPE_PREFIX_CA)) { + String type = key.substring(CLDRConverter.LOCALE_TYPE_PREFIX_CA.length()); for (CalendarType calendarType : CalendarType.values()) { if (calendarType == CalendarType.GENERIC) { continue; } if (type.equals(calendarType.lname())) { Object value = map.get(key); - formatData.put(key, value); - String ukey = CLDRConverter.CALENDAR_NAME_PREFIX + calendarType.uname(); - if (!key.equals(ukey)) { + String dataKey = key.replace(LOCALE_TYPE_PREFIX_CA, + CALENDAR_NAME_PREFIX); + formatData.put(dataKey, value); + String ukey = CALENDAR_NAME_PREFIX + calendarType.uname(); + if (!dataKey.equals(ukey)) { formatData.put(ukey, value); } } @@ -874,6 +795,18 @@ copyIfPresent(map, "NumberElements", formatData); } copyIfPresent(map, "NumberPatterns", formatData); + + // put extra number elements for available scripts into formatData, if it is "root" + if (id.equals("root")) { + handlerNumbering.keySet().stream() + .filter(k -> !numberingScripts.contains(k)) + .forEach(k -> { + String[] ne = (String[])map.get("latn.NumberElements"); + String[] neNew = Arrays.copyOf(ne, ne.length); + neNew[4] = handlerNumbering.get(k).substring(0, 1); + formatData.put(k + ".NumberElements", neNew); + }); + } return formatData; }
--- a/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java Wed Dec 13 13:27:45 2017 +0530 +++ b/make/jdk/src/classes/build/tools/cldrconverter/LDMLParseHandler.java Wed Dec 13 10:25:38 2017 -0800 @@ -76,12 +76,16 @@ // ignore this element - it has language and territory elements that aren't locale data pushIgnoredContainer(qName); break; - case "type": - if ("calendar".equals(attributes.getValue("key"))) { - pushStringEntry(qName, attributes, CLDRConverter.CALENDAR_NAME_PREFIX + attributes.getValue("type")); - } else { - pushIgnoredContainer(qName); - } + + // for LocaleNames + // copy string + case "localeSeparator": + pushStringEntry(qName, attributes, + CLDRConverter.LOCALE_SEPARATOR); + break; + case "localeKeyTypePattern": + pushStringEntry(qName, attributes, + CLDRConverter.LOCALE_KEYTYPE); break; case "language": @@ -96,6 +100,24 @@ attributes.getValue("type")); break; + case "key": + // for LocaleNames + // copy string + pushStringEntry(qName, attributes, + CLDRConverter.LOCALE_KEY_PREFIX + + convertOldKeyName(attributes.getValue("type"))); + break; + + case "type": + // for LocaleNames/CalendarNames + // copy string + pushStringEntry(qName, attributes, + CLDRConverter.LOCALE_TYPE_PREFIX + + convertOldKeyName(attributes.getValue("key")) + "." + + attributes.getValue("type")); + + break; + // // Currency information // @@ -515,26 +537,10 @@ currentNumberingSystem = script + "."; String digits = CLDRConverter.handlerNumbering.get(script); if (digits == null) { - throw new InternalError("null digits for " + script); - } - if (Character.isSurrogate(digits.charAt(0))) { - // DecimalFormatSymbols doesn't support supplementary characters as digit zero. pushIgnoredContainer(qName); break; } - // in case digits are in the reversed order, reverse back the order. - if (digits.charAt(0) > digits.charAt(digits.length() - 1)) { - StringBuilder sb = new StringBuilder(digits); - digits = sb.reverse().toString(); - } - // Check if the order is sequential. - char c0 = digits.charAt(0); - for (int i = 1; i < digits.length(); i++) { - if (digits.charAt(i) != c0 + i) { - pushIgnoredContainer(qName); - break symbols; - } - } + @SuppressWarnings("unchecked") List<String> numberingScripts = (List<String>) get("numberingScripts"); if (numberingScripts == null) { @@ -924,17 +930,35 @@ } } } else if (currentContainer instanceof Entry) { - Entry<?> entry = (Entry<?>) currentContainer; - Object value = entry.getValue(); - if (value != null) { - String key = entry.getKey(); - // Tweak for MonthNames for the root locale, Needed for - // SimpleDateFormat.format()/parse() roundtrip. - if (id.equals("root") && key.startsWith("MonthNames")) { - value = new DateFormatSymbols(Locale.US).getShortMonths(); - } - put(entry.getKey(), value); + Entry<?> entry = (Entry<?>) currentContainer; + Object value = entry.getValue(); + if (value != null) { + String key = entry.getKey(); + // Tweak for MonthNames for the root locale, Needed for + // SimpleDateFormat.format()/parse() roundtrip. + if (id.equals("root") && key.startsWith("MonthNames")) { + value = new DateFormatSymbols(Locale.US).getShortMonths(); } + put(entry.getKey(), value); } } } + + public String convertOldKeyName(String key) { + // Explicitly obtained from "alias" attribute in each "key" element. + switch (key) { + case "calendar": + return "ca"; + case "currency": + return "cu"; + case "collation": + return "co"; + case "numbers": + return "nu"; + case "timezone": + return "tz"; + default: + return key; + } + } +}
--- a/make/jdk/src/classes/build/tools/cldrconverter/NumberingSystemsParseHandler.java Wed Dec 13 13:27:45 2017 +0530 +++ b/make/jdk/src/classes/build/tools/cldrconverter/NumberingSystemsParseHandler.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,9 +54,32 @@ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { switch (qName) { case "numberingSystem": - if ("numeric".equals(attributes.getValue("type"))) { - // eg, <numberingSystem id="latn" type="numeric" digits="0123456789"/> - put(attributes.getValue("id"), attributes.getValue("digits")); + numberingSystem: { + if ("numeric".equals(attributes.getValue("type"))) { + // eg, <numberingSystem id="latn" type="numeric" digits="0123456789"/> + String script = attributes.getValue("id"); + String digits = attributes.getValue("digits"); + + if (Character.isSurrogate(digits.charAt(0))) { + // DecimalFormatSymbols doesn't support supplementary characters as digit zero. + break numberingSystem; + } + // in case digits are in the reversed order, reverse back the order. + if (digits.charAt(0) > digits.charAt(digits.length() - 1)) { + StringBuilder sb = new StringBuilder(digits); + digits = sb.reverse().toString(); + } + // Check if the order is sequential. + char c0 = digits.charAt(0); + for (int i = 1; i < digits.length(); i++) { + if (digits.charAt(i) != c0 + i) { + break numberingSystem; + } + } + + // script/digits are acceptable. + put(script, digits); + } } pushIgnoredContainer(qName); break;
--- a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java Wed Dec 13 13:27:45 2017 +0530 +++ b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -256,20 +256,21 @@ CLDRConverter.info("Generating file " + file); try (PrintWriter out = new PrintWriter(file, "us-ascii")) { - out.println(CopyrightHeaders.getOpenJDKCopyright()); + out.printf(CopyrightHeaders.getOpenJDKCopyright()); - out.println((CLDRConverter.isBaseModule ? "package sun.util.cldr;\n\n" : + out.printf((CLDRConverter.isBaseModule ? "package sun.util.cldr;\n\n" : "package sun.util.resources.cldr.provider;\n\n") + "import java.util.HashMap;\n" + "import java.util.Locale;\n" + "import java.util.Map;\n" - + "import sun.util.locale.provider.LocaleProviderAdapter;\n" - + "import sun.util.locale.provider.LocaleDataMetaInfo;\n"); + + "import sun.util.locale.provider.LocaleDataMetaInfo;\n" + + "import sun.util.locale.provider.LocaleProviderAdapter;\n\n"); out.printf("public class %s implements LocaleDataMetaInfo {\n", className); - out.println(" private static final Map<String, String> resourceNameToLocales = new HashMap<>();\n" + - (CLDRConverter.isBaseModule ? - " private static final Map<Locale, String[]> parentLocalesMap = new HashMap<>();\n\n" : "\n") + - " static {\n"); + out.printf(" private static final Map<String, String> resourceNameToLocales = new HashMap<>();\n" + + (CLDRConverter.isBaseModule ? + " private static final Map<Locale, String[]> parentLocalesMap = new HashMap<>();\n\n" : + "\n") + + " static {\n"); for (String key : metaInfo.keySet()) { if (key.startsWith(CLDRConverter.PARENT_LOCALE_PREFIX)) { @@ -296,30 +297,50 @@ } out.printf("\n });\n"); } else { - out.printf(" resourceNameToLocales.put(\"%s\",\n", key); - out.printf(" \"%s\");\n", - toLocaleList(key.equals("FormatData") ? metaInfo.get("AvailableLocales") : - metaInfo.get(key), false)); + if ("AvailableLocales".equals(key)) { + out.printf(" resourceNameToLocales.put(\"%s\",\n", key); + out.printf(" \"%s\");\n", toLocaleList(metaInfo.get(key), false)); + } } } - out.println(" }\n\n"); - out.println(" @Override\n" + + out.printf(" }\n\n"); + + // end of static initializer block. + + // Short TZ names for delayed initialization + if (CLDRConverter.isBaseModule) { + out.printf(" private static class TZShortIDMapHolder {\n"); + out.printf(" static final Map<String, String> tzShortIDMap = new HashMap<>();\n"); + out.printf(" static {\n"); + CLDRConverter.handlerTimeZone.getData().entrySet().stream() + .forEach(e -> { + out.printf(" tzShortIDMap.put(\"%s\", \"%s\");\n", e.getKey(), + ((String)e.getValue())); + }); + out.printf(" }\n }\n\n"); + } + + out.printf(" @Override\n" + " public LocaleProviderAdapter.Type getType() {\n" + " return LocaleProviderAdapter.Type.CLDR;\n" + " }\n\n"); - out.println(" @Override\n" + + out.printf(" @Override\n" + " public String availableLanguageTags(String category) {\n" + " return resourceNameToLocales.getOrDefault(category, \"\");\n" + " }\n\n"); if (CLDRConverter.isBaseModule) { + out.printf(" @Override\n" + + " public Map<String, String> tzShortIDs() {\n" + + " return TZShortIDMapHolder.tzShortIDMap;\n" + + " }\n\n"); out.printf(" public Map<Locale, String[]> parentLocales() {\n" + " return parentLocalesMap;\n" + " }\n}"); } else { - out.println("}"); + out.printf("}"); } } }
--- a/make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java Wed Dec 13 13:27:45 2017 +0530 +++ b/make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,53 +84,18 @@ values.put(CLDRConverter.PARENT_LOCALE_PREFIX+key, parentLocalesMap.get(key)); }); - } else { - String countryData = getWeekData(id, JAVA_FIRSTDAY, firstDayMap); - if (countryData != null) { - values.put(JAVA_FIRSTDAY, countryData); - } - String minDaysData = getWeekData(id, JAVA_MINDAY, minDaysMap); - if (minDaysData != null) { - values.put(JAVA_MINDAY, minDaysData); - } + firstDayMap.keySet().forEach(key -> { + values.put(CLDRConverter.CALENDAR_FIRSTDAY_PREFIX+firstDayMap.get(key), + key); + }); + minDaysMap.keySet().forEach(key -> { + values.put(CLDRConverter.CALENDAR_MINDAYS_PREFIX+minDaysMap.get(key), + key); + }); } return values.isEmpty() ? null : values; } - /** - * It returns either firstDay or minDays in the JRE format for the country. - * - * @param country territory code of the requested data - * @param jreDataName JAVA_FIRSTDAY or JAVA_MINDAY - * @param dataMap firstDayMap or minDaysMap - * @return the value for the given jreDataName, or null if requested value - * (firstDay/minDays) is not available although that is highly unlikely - * because of the default value for the world (001). - */ - String getWeekData(String country, final String jreDataName, final Map<String, Object> dataMap) { - String countryValue = null; - String defaultWorldValue = null; - for (String key : dataMap.keySet()) { - if (key.contains(country)) { - if (jreDataName.equals(JAVA_FIRSTDAY)) { - countryValue = DAY_OF_WEEK_MAP.get((String) dataMap.get(key)); - } else if (jreDataName.equals(JAVA_MINDAY)) { - countryValue = (String) dataMap.get(key); - } - if (countryValue != null) { - return countryValue; - } - } else if (key.contains(WORLD)) { - if (jreDataName.equals(JAVA_FIRSTDAY)) { - defaultWorldValue = DAY_OF_WEEK_MAP.get((String) dataMap.get(key)); - } else if (jreDataName.equals(JAVA_MINDAY)) { - defaultWorldValue = (String) dataMap.get(key); - } - } - } - return defaultWorldValue; - } - @Override public InputSource resolveEntity(String publicID, String systemID) throws IOException, SAXException { // avoid HTTP traffic to unicode.org @@ -152,7 +117,33 @@ switch (qName) { case "firstDay": if (!isIgnored(attributes)) { - firstDayMap.put(attributes.getValue("territories"), attributes.getValue("day")); + String fd; + + switch (attributes.getValue("day")) { + case "sun": + fd = "1"; + break; + default: + case "mon": + fd = "2"; + break; + case "tue": + fd = "3"; + break; + case "wed": + fd = "4"; + break; + case "thu": + fd = "5"; + break; + case "fri": + fd = "6"; + break; + case "sat": + fd = "7"; + break; + } + firstDayMap.put(attributes.getValue("territories"), fd); } break; case "minDays":
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/jdk/src/classes/build/tools/cldrconverter/TimeZoneParseHandler.java Wed Dec 13 10:25:38 2017 -0800 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package build.tools.cldrconverter; + +import java.io.File; +import java.io.IOException; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * Handles parsing of timezone.xml and produces a map from short timezone IDs to + * tz database IDs. + */ + +class TimeZoneParseHandler extends AbstractLDMLHandler<Object> { + + @Override + public InputSource resolveEntity(String publicID, String systemID) throws IOException, SAXException { + // avoid HTTP traffic to unicode.org + if (systemID.startsWith(CLDRConverter.BCP47_LDML_DTD_SYSTEM_ID)) { + return new InputSource((new File(CLDRConverter.LOCAL_BCP47_LDML_DTD)).toURI().toString()); + } + return null; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + switch (qName) { + case "type": + if (!isIgnored(attributes) && !attributes.getValue("deprecated").equals("true")) { + put(attributes.getValue("name"), attributes.getValue("alias")); + } + break; + default: + // treat anything else as a container + pushContainer(qName, attributes); + break; + } + } +}
--- a/make/nashorn/build.xml Wed Dec 13 13:27:45 2017 +0530 +++ b/make/nashorn/build.xml Wed Dec 13 10:25:38 2017 -0800 @@ -265,7 +265,7 @@ </target> <!-- generate javadoc for Nashorn classes --> - <target name="javadoc" depends="jar"> + <target name="javadoc" depends="jar" unless="test.class"> <javadoc destdir="${dist.javadoc.dir}" use="yes" windowtitle="${nashorn.product.name} ${nashorn.version}" additionalparam="-quiet" failonerror="true" useexternalfile="true">
--- a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package java.io; +import java.nio.charset.Charset; import java.util.Arrays; /** @@ -223,14 +224,27 @@ /** * Converts the buffer's contents into a string by decoding the bytes using - * the named {@link java.nio.charset.Charset charset}. The length of the new - * {@code String} is a function of the charset, and hence may not be equal - * to the length of the byte array. + * the named {@link java.nio.charset.Charset charset}. * - * <p> This method always replaces malformed-input and unmappable-character - * sequences with this charset's default replacement string. The {@link - * java.nio.charset.CharsetDecoder} class should be used when more control - * over the decoding process is required. + * <p> This method is equivalent to {@code #toString(charset)} that takes a + * {@link java.nio.charset.Charset charset}. + * + * <p> An invocation of this method of the form + * + * <pre> {@code + * ByteArrayOutputStream b = ... + * b.toString("UTF-8") + * } + * </pre> + * + * behaves in exactly the same way as the expression + * + * <pre> {@code + * ByteArrayOutputStream b = ... + * b.toString(StandardCharsets.UTF_8) + * } + * </pre> + * * * @param charsetName the name of a supported * {@link java.nio.charset.Charset charset} @@ -246,6 +260,26 @@ } /** + * Converts the buffer's contents into a string by decoding the bytes using + * the specified {@link java.nio.charset.Charset charset}. The length of the new + * {@code String} is a function of the charset, and hence may not be equal + * to the length of the byte array. + * + * <p> This method always replaces malformed-input and unmappable-character + * sequences with the charset's default replacement string. The {@link + * java.nio.charset.CharsetDecoder} class should be used when more control + * over the decoding process is required. + * + * @param charset the {@linkplain java.nio.charset.Charset charset} + * to be used to decode the {@code bytes} + * @return String decoded from the buffer's contents. + * @since 10 + */ + public synchronized String toString(Charset charset) { + return new String(buf, 0, count, charset); + } + + /** * Creates a newly allocated string. Its size is the current size of * the output stream and the valid contents of the buffer have been * copied into it. Each character <i>c</i> in the resulting string is @@ -257,9 +291,10 @@ * * @deprecated This method does not properly convert bytes into characters. * As of JDK 1.1, the preferred way to do this is via the - * {@code toString(String enc)} method, which takes an encoding-name - * argument, or the {@code toString()} method, which uses the - * platform's default character encoding. + * {@link #toString(String charsetName)} or {@link #toString(Charset charset)} + * method, which takes an encoding-name or charset argument, + * or the {@code toString()} method, which uses the platform's default + * character encoding. * * @param hibyte the high byte of each resulting Unicode character. * @return the current contents of the output stream, as a string.
--- a/src/java.base/share/classes/java/io/PrintStream.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/io/PrintStream.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,10 +45,16 @@ * ({@code '\n'}) is written. * * <p> All characters printed by a {@code PrintStream} are converted into - * bytes using the platform's default character encoding. + * bytes using the given encoding or charset, or platform's default character + * encoding if not specified. * The {@link PrintWriter} class should be used in situations that require * writing characters rather than bytes. * + * <p> This class always replaces malformed and unmappable character sequences with + * the charset's default replacement string. + * The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more + * control over the encoding process is required. + * * @author Frank Yellin * @author Mark Reinhold * @since 1.0 @@ -105,22 +111,13 @@ this.textOut = new BufferedWriter(charOut); } - private PrintStream(boolean autoFlush, OutputStream out, Charset charset) { - super(out); - this.autoFlush = autoFlush; - this.charOut = new OutputStreamWriter(this, charset); - this.textOut = new BufferedWriter(charOut); - } - /* Variant of the private constructor so that the given charset name * can be verified before evaluating the OutputStream argument. Used * by constructors creating a FileOutputStream that also take a * charset name. */ - private PrintStream(boolean autoFlush, Charset charset, OutputStream out) - throws UnsupportedEncodingException - { - this(autoFlush, out, charset); + private PrintStream(boolean autoFlush, Charset charset, OutputStream out) { + this(out, autoFlush, charset); } /** @@ -172,9 +169,30 @@ public PrintStream(OutputStream out, boolean autoFlush, String encoding) throws UnsupportedEncodingException { - this(autoFlush, - requireNonNull(out, "Null output stream"), - toCharset(encoding)); + this(requireNonNull(out, "Null output stream"), autoFlush, toCharset(encoding)); + } + + /** + * Creates a new print stream, with the specified OutputStream, automatic line + * flushing and charset. This convenience constructor creates the necessary + * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter}, + * which will encode characters using the provided charset. + * + * @param out The output stream to which values and objects will be + * printed + * @param autoFlush A boolean; if true, the output buffer will be flushed + * whenever a byte array is written, one of the + * {@code println} methods is invoked, or a newline + * character or byte ({@code '\n'}) is written + * @param charset A {@linkplain java.nio.charset.Charset charset} + * + * @since 10 + */ + public PrintStream(OutputStream out, boolean autoFlush, Charset charset) { + super(out); + this.autoFlush = autoFlush; + this.charOut = new OutputStreamWriter(this, charset); + this.textOut = new BufferedWriter(charOut); } /** @@ -250,6 +268,36 @@ /** * Creates a new print stream, without automatic line flushing, with the + * specified file name and charset. This convenience constructor creates + * the necessary intermediate {@link java.io.OutputStreamWriter + * OutputStreamWriter}, which will encode characters using the provided + * charset. + * + * @param fileName + * The name of the file to use as the destination of this print + * stream. If the file exists, then it will be truncated to + * zero size; otherwise, a new file will be created. The output + * will be written to the file and is buffered. + * + * @param charset + * A {@linkplain java.nio.charset.Charset charset} + * + * @throws IOException + * if an I/O error occurs while opening or creating the file + * + * @throws SecurityException + * If a security manager is present and {@link + * SecurityManager#checkWrite checkWrite(fileName)} denies write + * access to the file + * + * @since 10 + */ + public PrintStream(String fileName, Charset charset) throws IOException { + this(false, requireNonNull(charset, "charset"), new FileOutputStream(fileName)); + } + + /** + * Creates a new print stream, without automatic line flushing, with the * specified file. This convenience constructor creates the necessary * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter}, * which will encode characters using the {@linkplain @@ -319,6 +367,37 @@ this(false, toCharset(csn), new FileOutputStream(file)); } + + /** + * Creates a new print stream, without automatic line flushing, with the + * specified file and charset. This convenience constructor creates + * the necessary intermediate {@link java.io.OutputStreamWriter + * OutputStreamWriter}, which will encode characters using the provided + * charset. + * + * @param file + * The file to use as the destination of this print stream. If the + * file exists, then it will be truncated to zero size; otherwise, + * a new file will be created. The output will be written to the + * file and is buffered. + * + * @param charset + * A {@linkplain java.nio.charset.Charset charset} + * + * @throws IOException + * if an I/O error occurs while opening or creating the file + * + * @throws SecurityException + * If a security manager is present and {@link + * SecurityManager#checkWrite checkWrite(file.getPath())} + * denies write access to the file + * + * @since 10 + */ + public PrintStream(File file, Charset charset) throws IOException { + this(false, requireNonNull(charset, "charset"), new FileOutputStream(file)); + } + /** Check to make sure that the stream has not been closed */ private void ensureOpen() throws IOException { if (out == null)
--- a/src/java.base/share/classes/java/io/PrintWriter.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/io/PrintWriter.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,11 @@ * constructors may. The client may inquire as to whether any errors have * occurred by invoking {@link #checkError checkError()}. * + * <p> This class always replaces malformed and unmappable character sequences with + * the charset's default replacement string. + * The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more + * control over the encoding process is required. + * * @author Frank Yellin * @author Mark Reinhold * @since 1.1 @@ -137,7 +142,26 @@ * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream) */ public PrintWriter(OutputStream out, boolean autoFlush) { - this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush); + this(out, autoFlush, Charset.defaultCharset()); + } + + /** + * Creates a new PrintWriter from an existing OutputStream. This + * convenience constructor creates the necessary intermediate + * OutputStreamWriter, which will convert characters into bytes using the + * specified charset. + * + * @param out An output stream + * @param autoFlush A boolean; if true, the {@code println}, + * {@code printf}, or {@code format} methods will + * flush the output buffer + * @param charset + * A {@linkplain java.nio.charset.Charset charset} + * + * @since 10 + */ + public PrintWriter(OutputStream out, boolean autoFlush, Charset charset) { + this(new BufferedWriter(new OutputStreamWriter(out, charset)), autoFlush); // save print stream for error propagation if (out instanceof java.io.PrintStream) { @@ -226,6 +250,36 @@ /** * Creates a new PrintWriter, without automatic line flushing, with the + * specified file name and charset. This convenience constructor creates + * the necessary intermediate {@link java.io.OutputStreamWriter + * OutputStreamWriter}, which will encode characters using the provided + * charset. + * + * @param fileName + * The name of the file to use as the destination of this writer. + * If the file exists then it will be truncated to zero size; + * otherwise, a new file will be created. The output will be + * written to the file and is buffered. + * + * @param charset + * A {@linkplain java.nio.charset.Charset charset} + * + * @throws IOException + * if an I/O error occurs while opening or creating the file + * + * @throws SecurityException + * If a security manager is present and {@link + * SecurityManager#checkWrite checkWrite(fileName)} denies write + * access to the file + * + * @since 10 + */ + public PrintWriter(String fileName, Charset charset) throws IOException { + this(Objects.requireNonNull(charset, "charset"), new File(fileName)); + } + + /** + * Creates a new PrintWriter, without automatic line flushing, with the * specified file. This convenience constructor creates the necessary * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter}, * which will encode characters using the {@linkplain @@ -295,6 +349,36 @@ this(toCharset(csn), file); } + /** + * Creates a new PrintWriter, without automatic line flushing, with the + * specified file and charset. This convenience constructor creates the + * necessary intermediate {@link java.io.OutputStreamWriter + * OutputStreamWriter}, which will encode characters using the provided + * charset. + * + * @param file + * The file to use as the destination of this writer. If the file + * exists then it will be truncated to zero size; otherwise, a new + * file will be created. The output will be written to the file + * and is buffered. + * + * @param charset + * A {@linkplain java.nio.charset.Charset charset} + * + * @throws IOException + * if an I/O error occurs while opening or creating the file + * + * @throws SecurityException + * If a security manager is present and {@link + * SecurityManager#checkWrite checkWrite(file.getPath())} + * denies write access to the file + * + * @since 10 + */ + public PrintWriter(File file, Charset charset) throws IOException { + this(Objects.requireNonNull(charset, "charset"), file); + } + /** Checks to make sure that the stream has not been closed */ private void ensureOpen() throws IOException { if (out == null)
--- a/src/java.base/share/classes/java/lang/String.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/lang/String.java Wed Dec 13 10:25:38 2017 -0800 @@ -3046,6 +3046,10 @@ return COMPACT_STRINGS ? coder : UTF16; } + byte[] value() { + return value; + } + private boolean isLatin1() { return COMPACT_STRINGS && coder == LATIN1; }
--- a/src/java.base/share/classes/java/lang/StringCoding.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/lang/StringCoding.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,11 @@ import static java.lang.String.LATIN1; import static java.lang.String.UTF16; import static java.lang.String.COMPACT_STRINGS; +import static java.lang.Character.isSurrogate; +import static java.lang.Character.highSurrogate; +import static java.lang.Character.lowSurrogate; +import static java.lang.Character.isSupplementaryCodePoint; +import static java.lang.StringUTF16.putChar; /** * Utility class for string encoding and decoding. @@ -66,8 +71,6 @@ private static final Charset US_ASCII = sun.nio.cs.US_ASCII.INSTANCE; private static final Charset UTF_8 = sun.nio.cs.UTF_8.INSTANCE; - private static boolean warnUnsupportedCharset = true; - private static <T> T deref(ThreadLocal<SoftReference<T>> tl) { SoftReference<T> sr = tl.get(); if (sr == null) @@ -80,7 +83,6 @@ } // Trim the given byte array to the given length - // private static byte[] safeTrim(byte[] ba, int len, boolean isTrusted) { if (len == ba.length && (isTrusted || System.getSecurityManager() == null)) return ba; @@ -105,17 +107,6 @@ return null; } - private static void warnUnsupportedCharset(String csn) { - if (warnUnsupportedCharset) { - // Use err(String) rather than the Logging API or System.err - // since this method may be called during VM initialization - // before either is available. - err("WARNING: Default charset " + csn + - " not supported, using ISO-8859-1 instead\n"); - warnUnsupportedCharset = false; - } - } - static class Result { byte[] value; byte coder; @@ -224,19 +215,6 @@ } } - private static class StringDecoder8859_1 extends StringDecoder { - StringDecoder8859_1(Charset cs, String rcn) { - super(cs, rcn); - } - Result decode(byte[] ba, int off, int len) { - if (COMPACT_STRINGS) { - return result.with(Arrays.copyOfRange(ba, off, off + len), LATIN1); - } else { - return result.with(StringLatin1.inflate(ba, off, len), UTF16); - } - } - } - static Result decode(String charsetName, byte[] ba, int off, int len) throws UnsupportedEncodingException { @@ -249,12 +227,15 @@ Charset cs = lookupCharset(csn); if (cs != null) { if (cs == UTF_8) { - sd = new StringDecoderUTF8(cs, csn); - } else if (cs == ISO_8859_1) { - sd = new StringDecoder8859_1(cs, csn); - } else { - sd = new StringDecoder(cs, csn); + return decodeUTF8(ba, off, len, true); } + if (cs == ISO_8859_1) { + return decodeLatin1(ba, off, len); + } + if (cs == US_ASCII) { + return decodeASCII(ba, off, len); + } + sd = new StringDecoder(cs, csn); } } catch (IllegalCharsetNameException x) {} if (sd == null) @@ -265,6 +246,16 @@ } static Result decode(Charset cs, byte[] ba, int off, int len) { + if (cs == UTF_8) { + return decodeUTF8(ba, off, len, true); + } + if (cs == ISO_8859_1) { + return decodeLatin1(ba, off, len); + } + if (cs == US_ASCII) { + return decodeASCII(ba, off, len); + } + // (1)We never cache the "external" cs, the only benefit of creating // an additional StringDe/Encoder object to wrap it is to share the // de/encode() method. These SD/E objects are short-lived, the young-gen @@ -280,39 +271,29 @@ // check (... && (isTrusted || SM == null || getClassLoader0())) in trim // but it then can be argued that the SM is null when the operation // is started... - if (cs == UTF_8) { - return StringDecoderUTF8.decode(ba, off, len, new Result()); - } CharsetDecoder cd = cs.newDecoder(); // ascii fastpath - if (cs == ISO_8859_1 || ((cd instanceof ArrayDecoder) && - ((ArrayDecoder)cd).isASCIICompatible() && - !hasNegatives(ba, off, len))) { - if (COMPACT_STRINGS) { - return new Result().with(Arrays.copyOfRange(ba, off, off + len), - LATIN1); - } else { - return new Result().with(StringLatin1.inflate(ba, off, len), UTF16); - } + if ((cd instanceof ArrayDecoder) && + ((ArrayDecoder)cd).isASCIICompatible() && !hasNegatives(ba, off, len)) { + return decodeLatin1(ba, off, len); } int en = scale(len, cd.maxCharsPerByte()); if (len == 0) { return new Result().with(); } - if (cs.getClass().getClassLoader0() != null && - System.getSecurityManager() != null) { - ba = Arrays.copyOfRange(ba, off, off + len); - off = 0; - } cd.onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE) .reset(); - char[] ca = new char[en]; if (cd instanceof ArrayDecoder) { int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca); return new Result().with(ca, 0, clen); } + if (cs.getClass().getClassLoader0() != null && + System.getSecurityManager() != null) { + ba = Arrays.copyOfRange(ba, off, off + len); + off = 0; + } ByteBuffer bb = ByteBuffer.wrap(ba, off, len); CharBuffer cb = CharBuffer.wrap(ca); try { @@ -331,24 +312,22 @@ } static Result decode(byte[] ba, int off, int len) { - String csn = Charset.defaultCharset().name(); - try { - // use charset name decode() variant which provides caching. - return decode(csn, ba, off, len); - } catch (UnsupportedEncodingException x) { - warnUnsupportedCharset(csn); + Charset cs = Charset.defaultCharset(); + if (cs == UTF_8) { + return decodeUTF8(ba, off, len, true); } - try { - return decode("ISO-8859-1", ba, off, len); - } catch (UnsupportedEncodingException x) { - // If this code is hit during VM initialization, err(String) is - // the only way we will be able to get any kind of error message. - err("ISO-8859-1 charset not available: " + x.toString() + "\n"); - // If we can not find ISO-8859-1 (a required encoding) then things - // are seriously wrong with the installation. - System.exit(1); - return null; + if (cs == ISO_8859_1) { + return decodeLatin1(ba, off, len); } + if (cs == US_ASCII) { + return decodeASCII(ba, off, len); + } + StringDecoder sd = deref(decoder); + if (sd == null || !cs.name().equals(sd.cs.name())) { + sd = new StringDecoder(cs, cs.name()); + set(decoder, sd); + } + return sd.decode(ba, off, len); } // -- Encoding -- @@ -393,9 +372,6 @@ return ba; } if (ce instanceof ArrayEncoder) { - if (!isTrusted) { - val = Arrays.copyOf(val, val.length); - } int blen = (coder == LATIN1 ) ? ((ArrayEncoder)ce).encodeFromLatin1(val, 0, len, ba) : ((ArrayEncoder)ce).encodeFromUTF16(val, 0, len, ba); if (blen != -1) { @@ -423,49 +399,140 @@ } } - @HotSpotIntrinsicCandidate - private static int implEncodeISOArray(byte[] sa, int sp, - byte[] da, int dp, int len) { - int i = 0; - for (; i < len; i++) { - char c = StringUTF16.getChar(sa, sp++); - if (c > '\u00FF') - break; - da[dp++] = (byte)c; + static byte[] encode(String charsetName, byte coder, byte[] val) + throws UnsupportedEncodingException + { + StringEncoder se = deref(encoder); + String csn = (charsetName == null) ? "ISO-8859-1" : charsetName; + if ((se == null) || !(csn.equals(se.requestedCharsetName()) + || csn.equals(se.charsetName()))) { + se = null; + try { + Charset cs = lookupCharset(csn); + if (cs != null) { + if (cs == UTF_8) { + return encodeUTF8(coder, val, true); + } + if (cs == ISO_8859_1) { + return encode8859_1(coder, val); + } + if (cs == US_ASCII) { + return encodeASCII(coder, val); + } + se = new StringEncoder(cs, csn); + } + } catch (IllegalCharsetNameException x) {} + if (se == null) { + throw new UnsupportedEncodingException (csn); + } + set(encoder, se); } - return i; + return se.encode(coder, val); } - static byte[] encode8859_1(byte coder, byte[] val) { - if (coder == LATIN1) { + static byte[] encode(Charset cs, byte coder, byte[] val) { + if (cs == UTF_8) { + return encodeUTF8(coder, val, true); + } + if (cs == ISO_8859_1) { + return encode8859_1(coder, val); + } + if (cs == US_ASCII) { + return encodeASCII(coder, val); + } + CharsetEncoder ce = cs.newEncoder(); + // fastpath for ascii compatible + if (coder == LATIN1 && (((ce instanceof ArrayEncoder) && + ((ArrayEncoder)ce).isASCIICompatible() && + !hasNegatives(val, 0, val.length)))) { return Arrays.copyOf(val, val.length); } - int len = val.length >> 1; - byte[] dst = new byte[len]; - int dp = 0; - int sp = 0; - int sl = len; - while (sp < sl) { - int ret = implEncodeISOArray(val, sp, dst, dp, len); - sp = sp + ret; - dp = dp + ret; - if (ret != len) { - char c = StringUTF16.getChar(val, sp++); - if (Character.isHighSurrogate(c) && sp < sl && - Character.isLowSurrogate(StringUTF16.getChar(val, sp))) { - sp++; - } - dst[dp++] = '?'; - len = sl - sp; + int len = val.length >> coder; // assume LATIN1=0/UTF16=1; + int en = scale(len, ce.maxBytesPerChar()); + byte[] ba = new byte[en]; + if (len == 0) { + return ba; + } + ce.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE) + .reset(); + if (ce instanceof ArrayEncoder) { + int blen = (coder == LATIN1 ) ? ((ArrayEncoder)ce).encodeFromLatin1(val, 0, len, ba) + : ((ArrayEncoder)ce).encodeFromUTF16(val, 0, len, ba); + if (blen != -1) { + return safeTrim(ba, blen, true); } } - if (dp == dst.length) { - return dst; + boolean isTrusted = cs.getClass().getClassLoader0() == null || + System.getSecurityManager() == null; + char[] ca = (coder == LATIN1 ) ? StringLatin1.toChars(val) + : StringUTF16.toChars(val); + ByteBuffer bb = ByteBuffer.wrap(ba); + CharBuffer cb = CharBuffer.wrap(ca, 0, len); + try { + CoderResult cr = ce.encode(cb, bb, true); + if (!cr.isUnderflow()) + cr.throwException(); + cr = ce.flush(bb); + if (!cr.isUnderflow()) + cr.throwException(); + } catch (CharacterCodingException x) { + throw new Error(x); } - return Arrays.copyOf(dst, dp); + return safeTrim(ba, bb.position(), isTrusted); } - static byte[] encodeASCII(byte coder, byte[] val) { + static byte[] encode(byte coder, byte[] val) { + Charset cs = Charset.defaultCharset(); + if (cs == UTF_8) { + return encodeUTF8(coder, val, true); + } + if (cs == ISO_8859_1) { + return encode8859_1(coder, val); + } + if (cs == US_ASCII) { + return encodeASCII(coder, val); + } + StringEncoder se = deref(encoder); + if (se == null || !cs.name().equals(se.cs.name())) { + se = new StringEncoder(cs, cs.name()); + set(encoder, se); + } + return se.encode(coder, val); + } + + /** + * Print a message directly to stderr, bypassing all character conversion + * methods. + * @param msg message to print + */ + private static native void err(String msg); + + /* The cached Result for each thread */ + private static final ThreadLocal<StringCoding.Result> + resultCached = new ThreadLocal<>() { + protected StringCoding.Result initialValue() { + return new StringCoding.Result(); + }}; + + ////////////////////////// ascii ////////////////////////////// + + private static Result decodeASCII(byte[] ba, int off, int len) { + Result result = resultCached.get(); + if (COMPACT_STRINGS && !hasNegatives(ba, off, len)) { + return result.with(Arrays.copyOfRange(ba, off, off + len), + LATIN1); + } + byte[] dst = new byte[len<<1]; + int dp = 0; + while (dp < len) { + int b = ba[off++]; + putChar(dst, dp++, (b >= 0) ? (char)b : repl); + } + return result.with(dst, UTF16); + } + + private static byte[] encodeASCII(byte coder, byte[] val) { if (coder == LATIN1) { byte[] dst = new byte[val.length]; for (int i = 0; i < val.length; i++) { @@ -498,59 +565,51 @@ return Arrays.copyOf(dst, dp); } - static byte[] encodeUTF8(byte coder, byte[] val) { + ////////////////////////// latin1/8859_1 /////////////////////////// + + private static Result decodeLatin1(byte[] ba, int off, int len) { + Result result = resultCached.get(); + if (COMPACT_STRINGS) { + return result.with(Arrays.copyOfRange(ba, off, off + len), LATIN1); + } else { + return result.with(StringLatin1.inflate(ba, off, len), UTF16); + } + } + + @HotSpotIntrinsicCandidate + private static int implEncodeISOArray(byte[] sa, int sp, + byte[] da, int dp, int len) { + int i = 0; + for (; i < len; i++) { + char c = StringUTF16.getChar(sa, sp++); + if (c > '\u00FF') + break; + da[dp++] = (byte)c; + } + return i; + } + + private static byte[] encode8859_1(byte coder, byte[] val) { + if (coder == LATIN1) { + return Arrays.copyOf(val, val.length); + } + int len = val.length >> 1; + byte[] dst = new byte[len]; int dp = 0; - byte[] dst; - if (coder == LATIN1) { - dst = new byte[val.length << 1]; - for (int sp = 0; sp < val.length; sp++) { - byte c = val[sp]; - if (c < 0) { - dst[dp++] = (byte)(0xc0 | ((c & 0xff) >> 6)); - dst[dp++] = (byte)(0x80 | (c & 0x3f)); - } else { - dst[dp++] = c; + int sp = 0; + int sl = len; + while (sp < sl) { + int ret = implEncodeISOArray(val, sp, dst, dp, len); + sp = sp + ret; + dp = dp + ret; + if (ret != len) { + char c = StringUTF16.getChar(val, sp++); + if (Character.isHighSurrogate(c) && sp < sl && + Character.isLowSurrogate(StringUTF16.getChar(val, sp))) { + sp++; } - } - } else { - int sp = 0; - int sl = val.length >> 1; - dst = new byte[sl * 3]; - char c; - while (sp < sl && (c = StringUTF16.getChar(val, sp)) < '\u0080') { - // ascii fast loop; - dst[dp++] = (byte)c; - sp++; - } - while (sp < sl) { - c = StringUTF16.getChar(val, sp++); - if (c < 0x80) { - dst[dp++] = (byte)c; - } else if (c < 0x800) { - dst[dp++] = (byte)(0xc0 | (c >> 6)); - dst[dp++] = (byte)(0x80 | (c & 0x3f)); - } else if (Character.isSurrogate(c)) { - int uc = -1; - char c2; - if (Character.isHighSurrogate(c) && sp < sl && - Character.isLowSurrogate(c2 = StringUTF16.getChar(val, sp))) { - uc = Character.toCodePoint(c, c2); - } - if (uc < 0) { - dst[dp++] = '?'; - } else { - dst[dp++] = (byte)(0xf0 | ((uc >> 18))); - dst[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f)); - dst[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f)); - dst[dp++] = (byte)(0x80 | (uc & 0x3f)); - sp++; // 2 chars - } - } else { - // 3 bytes, 16 bits - dst[dp++] = (byte)(0xe0 | ((c >> 12))); - dst[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f)); - dst[dp++] = (byte)(0x80 | (c & 0x3f)); - } + dst[dp++] = '?'; + len = sl - sp; } } if (dp == dst.length) { @@ -559,113 +618,333 @@ return Arrays.copyOf(dst, dp); } - static byte[] encode(String charsetName, byte coder, byte[] val) - throws UnsupportedEncodingException - { - StringEncoder se = deref(encoder); - String csn = (charsetName == null) ? "ISO-8859-1" : charsetName; - if ((se == null) || !(csn.equals(se.requestedCharsetName()) - || csn.equals(se.charsetName()))) { - se = null; - try { - Charset cs = lookupCharset(csn); - if (cs != null) { - if (cs == UTF_8) { - return encodeUTF8(coder, val); - } else if (cs == ISO_8859_1) { - return encode8859_1(coder, val); - } else if (cs == US_ASCII) { - return encodeASCII(coder, val); - } - se = new StringEncoder(cs, csn); - } - } catch (IllegalCharsetNameException x) {} - if (se == null) { - throw new UnsupportedEncodingException (csn); - } - set(encoder, se); - } - return se.encode(coder, val); + //////////////////////////////// utf8 //////////////////////////////////// + + private static boolean isNotContinuation(int b) { + return (b & 0xc0) != 0x80; } - static byte[] encode(Charset cs, byte coder, byte[] val) { - if (cs == UTF_8) { - return encodeUTF8(coder, val); - } else if (cs == ISO_8859_1) { - return encode8859_1(coder, val); - } else if (cs == US_ASCII) { - return encodeASCII(coder, val); + private static boolean isMalformed3(int b1, int b2, int b3) { + return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || + (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80; + } + + private static boolean isMalformed3_2(int b1, int b2) { + return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || + (b2 & 0xc0) != 0x80; + } + + private static boolean isMalformed4(int b2, int b3, int b4) { + return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 || + (b4 & 0xc0) != 0x80; + } + + private static boolean isMalformed4_2(int b1, int b2) { + return (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) || + (b1 == 0xf4 && (b2 & 0xf0) != 0x80) || + (b2 & 0xc0) != 0x80; + } + + private static boolean isMalformed4_3(int b3) { + return (b3 & 0xc0) != 0x80; + } + + // for nb == 3/4 + private static int malformedN(byte[] src, int sp, int nb) { + if (nb == 3) { + int b1 = src[sp++]; + int b2 = src[sp++]; // no need to lookup b3 + return ((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || + isNotContinuation(b2)) ? 1 : 2; + } else if (nb == 4) { // we don't care the speed here + int b1 = src[sp++] & 0xff; + int b2 = src[sp++] & 0xff; + if (b1 > 0xf4 || + (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) || + (b1 == 0xf4 && (b2 & 0xf0) != 0x80) || + isNotContinuation(b2)) + return 1; + if (isNotContinuation(src[sp++])) + return 2; + return 3; } - CharsetEncoder ce = cs.newEncoder(); - // fastpath for ascii compatible - if (coder == LATIN1 && (((ce instanceof ArrayEncoder) && - ((ArrayEncoder)ce).isASCIICompatible() && - !hasNegatives(val, 0, val.length)))) { - return Arrays.copyOf(val, val.length); - } - int len = val.length >> coder; // assume LATIN1=0/UTF16=1; - int en = scale(len, ce.maxBytesPerChar()); - byte[] ba = new byte[en]; - if (len == 0) { - return ba; - } - boolean isTrusted = cs.getClass().getClassLoader0() == null || - System.getSecurityManager() == null; - ce.onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE) - .reset(); - if (ce instanceof ArrayEncoder) { - if (!isTrusted) { - val = Arrays.copyOf(val, val.length); + assert false; + return -1; + } + + private static void throwMalformed(int off, int nb) { + throw new IllegalArgumentException("malformed input off : " + off + + ", length : " + nb); + } + + private static char repl = '\ufffd'; + + private static Result decodeUTF8(byte[] src, int sp, int len, boolean doReplace) { + // ascii-bais, which has a relative impact to the non-ascii-only bytes + if (COMPACT_STRINGS && !hasNegatives(src, sp, len)) + return resultCached.get().with(Arrays.copyOfRange(src, sp, sp + len), + LATIN1); + return decodeUTF8_0(src, sp, len, doReplace); + } + + private static Result decodeUTF8_0(byte[] src, int sp, int len, boolean doReplace) { + Result ret = resultCached.get(); + + int sl = sp + len; + int dp = 0; + byte[] dst = new byte[len]; + + if (COMPACT_STRINGS) { + while (sp < sl) { + int b1 = src[sp]; + if (b1 >= 0) { + dst[dp++] = (byte)b1; + sp++; + continue; + } + if ((b1 == (byte)0xc2 || b1 == (byte)0xc3) && + sp + 1 < sl) { + int b2 = src[sp + 1]; + if (!isNotContinuation(b2)) { + dst[dp++] = (byte)(((b1 << 6) ^ b2)^ + (((byte) 0xC0 << 6) ^ + ((byte) 0x80 << 0))); + sp += 2; + continue; + } + } + // anything not a latin1, including the repl + // we have to go with the utf16 + break; } - int blen = (coder == LATIN1 ) ? ((ArrayEncoder)ce).encodeFromLatin1(val, 0, len, ba) - : ((ArrayEncoder)ce).encodeFromUTF16(val, 0, len, ba); - if (blen != -1) { - return safeTrim(ba, blen, isTrusted); + if (sp == sl) { + if (dp != dst.length) { + dst = Arrays.copyOf(dst, dp); + } + return ret.with(dst, LATIN1); } } - char[] ca = (coder == LATIN1 ) ? StringLatin1.toChars(val) - : StringUTF16.toChars(val); - ByteBuffer bb = ByteBuffer.wrap(ba); - CharBuffer cb = CharBuffer.wrap(ca, 0, len); - try { - CoderResult cr = ce.encode(cb, bb, true); - if (!cr.isUnderflow()) - cr.throwException(); - cr = ce.flush(bb); - if (!cr.isUnderflow()) - cr.throwException(); - } catch (CharacterCodingException x) { - throw new Error(x); + if (dp == 0) { + dst = new byte[len << 1]; + } else { + byte[] buf = new byte[len << 1]; + StringLatin1.inflate(dst, 0, buf, 0, dp); + dst = buf; } - return safeTrim(ba, bb.position(), isTrusted); + while (sp < sl) { + int b1 = src[sp++]; + if (b1 >= 0) { + putChar(dst, dp++, (char) b1); + } else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) { + if (sp < sl) { + int b2 = src[sp++]; + if (isNotContinuation(b2)) { + if (!doReplace) { + throwMalformed(sp - 1, 1); + } + putChar(dst, dp++, repl); + sp--; + } else { + putChar(dst, dp++, (char)(((b1 << 6) ^ b2)^ + (((byte) 0xC0 << 6) ^ + ((byte) 0x80 << 0)))); + } + continue; + } + if (!doReplace) { + throwMalformed(sp, 1); // underflow() + } + putChar(dst, dp++, repl); + break; + } else if ((b1 >> 4) == -2) { + if (sp + 1 < sl) { + int b2 = src[sp++]; + int b3 = src[sp++]; + if (isMalformed3(b1, b2, b3)) { + if (!doReplace) { + throwMalformed(sp - 3, 3); + } + putChar(dst, dp++, repl); + sp -= 3; + sp += malformedN(src, sp, 3); + } else { + char c = (char)((b1 << 12) ^ + (b2 << 6) ^ + (b3 ^ + (((byte) 0xE0 << 12) ^ + ((byte) 0x80 << 6) ^ + ((byte) 0x80 << 0)))); + if (isSurrogate(c)) { + if (!doReplace) { + throwMalformed(sp - 3, 3); + } + putChar(dst, dp++, repl); + } else { + putChar(dst, dp++, c); + } + } + continue; + } + if (sp < sl && isMalformed3_2(b1, src[sp])) { + if (!doReplace) { + throwMalformed(sp - 1, 2); + } + putChar(dst, dp++, repl); + continue; + } + if (!doReplace){ + throwMalformed(sp, 1); + } + putChar(dst, dp++, repl); + break; + } else if ((b1 >> 3) == -2) { + if (sp + 2 < sl) { + int b2 = src[sp++]; + int b3 = src[sp++]; + int b4 = src[sp++]; + int uc = ((b1 << 18) ^ + (b2 << 12) ^ + (b3 << 6) ^ + (b4 ^ + (((byte) 0xF0 << 18) ^ + ((byte) 0x80 << 12) ^ + ((byte) 0x80 << 6) ^ + ((byte) 0x80 << 0)))); + if (isMalformed4(b2, b3, b4) || + !isSupplementaryCodePoint(uc)) { // shortest form check + if (!doReplace) { + throwMalformed(sp - 4, 4); + } + putChar(dst, dp++, repl); + sp -= 4; + sp += malformedN(src, sp, 4); + } else { + putChar(dst, dp++, highSurrogate(uc)); + putChar(dst, dp++, lowSurrogate(uc)); + } + continue; + } + b1 &= 0xff; + if (b1 > 0xf4 || + sp < sl && isMalformed4_2(b1, src[sp] & 0xff)) { + if (!doReplace) { + throwMalformed(sp - 1, 1); // or 2 + } + putChar(dst, dp++, repl); + continue; + } + if (!doReplace) { + throwMalformed(sp - 1, 1); + } + sp++; + putChar(dst, dp++, repl); + if (sp < sl && isMalformed4_3(src[sp])) { + continue; + } + break; + } else { + if (!doReplace) { + throwMalformed(sp - 1, 1); + } + putChar(dst, dp++, repl); + } + } + if (dp != len) { + dst = Arrays.copyOf(dst, dp << 1); + } + return ret.with(dst, UTF16); } - static byte[] encode(byte coder, byte[] val) { - String csn = Charset.defaultCharset().name(); - try { - // use charset name encode() variant which provides caching. - return encode(csn, coder, val); - } catch (UnsupportedEncodingException x) { - warnUnsupportedCharset(csn); + private static byte[] encodeUTF8(byte coder, byte[] val, boolean doReplace) { + if (coder == UTF16) + return encodeUTF8_UTF16(val, doReplace); + + if (!hasNegatives(val, 0, val.length)) + return Arrays.copyOf(val, val.length); + + int dp = 0; + byte[] dst = new byte[val.length << 1]; + for (int sp = 0; sp < val.length; sp++) { + byte c = val[sp]; + if (c < 0) { + dst[dp++] = (byte)(0xc0 | ((c & 0xff) >> 6)); + dst[dp++] = (byte)(0x80 | (c & 0x3f)); + } else { + dst[dp++] = c; + } } - try { - return encode("ISO-8859-1", coder, val); - } catch (UnsupportedEncodingException x) { - // If this code is hit during VM initialization, err(String) is - // the only way we will be able to get any kind of error message. - err("ISO-8859-1 charset not available: " + x.toString() + "\n"); - // If we can not find ISO-8859-1 (a required encoding) then things - // are seriously wrong with the installation. - System.exit(1); - return null; - } + if (dp == dst.length) + return dst; + return Arrays.copyOf(dst, dp); } - /** - * Print a message directly to stderr, bypassing all character conversion - * methods. - * @param msg message to print + private static byte[] encodeUTF8_UTF16(byte[] val, boolean doReplace) { + int dp = 0; + int sp = 0; + int sl = val.length >> 1; + byte[] dst = new byte[sl * 3]; + char c; + while (sp < sl && (c = StringUTF16.getChar(val, sp)) < '\u0080') { + // ascii fast loop; + dst[dp++] = (byte)c; + sp++; + } + while (sp < sl) { + c = StringUTF16.getChar(val, sp++); + if (c < 0x80) { + dst[dp++] = (byte)c; + } else if (c < 0x800) { + dst[dp++] = (byte)(0xc0 | (c >> 6)); + dst[dp++] = (byte)(0x80 | (c & 0x3f)); + } else if (Character.isSurrogate(c)) { + int uc = -1; + char c2; + if (Character.isHighSurrogate(c) && sp < sl && + Character.isLowSurrogate(c2 = StringUTF16.getChar(val, sp))) { + uc = Character.toCodePoint(c, c2); + } + if (uc < 0) { + if (doReplace) { + dst[dp++] = '?'; + } else { + throwMalformed(sp - 1, 1); // or 2, does not matter here + } + } else { + dst[dp++] = (byte)(0xf0 | ((uc >> 18))); + dst[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f)); + dst[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f)); + dst[dp++] = (byte)(0x80 | (uc & 0x3f)); + sp++; // 2 chars + } + } else { + // 3 bytes, 16 bits + dst[dp++] = (byte)(0xe0 | ((c >> 12))); + dst[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f)); + dst[dp++] = (byte)(0x80 | (c & 0x3f)); + } + } + if (dp == dst.length) { + return dst; + } + return Arrays.copyOf(dst, dp); + } + + ////////////////////// for j.u.z.ZipCoder ////////////////////////// + + /* + * Throws iae, instead of replacing, if malformed or unmappble. */ - private static native void err(String msg); + static String newStringUTF8NoRepl(byte[] src, int off, int len) { + if (COMPACT_STRINGS && !hasNegatives(src, off, len)) + return new String(Arrays.copyOfRange(src, off, off + len), LATIN1); + Result ret = decodeUTF8_0(src, off, len, false); + return new String(ret.value, ret.coder); + } + + /* + * Throws iae, instead of replacing, if unmappble. + */ + static byte[] getBytesUTF8NoRepl(String s) { + return encodeUTF8(s.coder(), s.value(), false); + } }
--- a/src/java.base/share/classes/java/lang/StringDecoderUTF8.java Wed Dec 13 13:27:45 2017 +0530 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,235 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.lang; - -import java.nio.charset.Charset; -import java.util.Arrays; - -import static java.lang.String.LATIN1; -import static java.lang.String.UTF16; -import static java.lang.String.COMPACT_STRINGS; -import static java.lang.Character.isSurrogate; -import static java.lang.Character.highSurrogate; -import static java.lang.Character.lowSurrogate; -import static java.lang.Character.isSupplementaryCodePoint; -import static java.lang.StringUTF16.putChar; - -class StringDecoderUTF8 extends StringCoding.StringDecoder { - - StringDecoderUTF8(Charset cs, String rcn) { - super(cs, rcn); - } - - private static boolean isNotContinuation(int b) { - return (b & 0xc0) != 0x80; - } - - private static boolean isMalformed3(int b1, int b2, int b3) { - return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || - (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80; - } - - private static boolean isMalformed3_2(int b1, int b2) { - return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || - (b2 & 0xc0) != 0x80; - } - - private static boolean isMalformed4(int b2, int b3, int b4) { - return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 || - (b4 & 0xc0) != 0x80; - } - - private static boolean isMalformed4_2(int b1, int b2) { - return (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) || - (b1 == 0xf4 && (b2 & 0xf0) != 0x80) || - (b2 & 0xc0) != 0x80; - } - - private static boolean isMalformed4_3(int b3) { - return (b3 & 0xc0) != 0x80; - } - - // for nb == 3/4 - private static int malformedN(byte[] src, int sp, int nb) { - if (nb == 3) { - int b1 = src[sp++]; - int b2 = src[sp++]; // no need to lookup b3 - return ((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || - isNotContinuation(b2)) ? 1 : 2; - } else if (nb == 4) { // we don't care the speed here - int b1 = src[sp++] & 0xff; - int b2 = src[sp++] & 0xff; - if (b1 > 0xf4 || - (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) || - (b1 == 0xf4 && (b2 & 0xf0) != 0x80) || - isNotContinuation(b2)) - return 1; - if (isNotContinuation(src[sp++])) - return 2; - return 3; - } - assert false; - return -1; - } - - private static char repl = '\ufffd'; - - StringCoding.Result decode(byte[] src, int sp, int len) { - return decode(src, sp, len, result); - } - - static StringCoding.Result decode(byte[] src, int sp, int len, - StringCoding.Result ret) { - int sl = sp + len; - byte[] dst = new byte[len]; - int dp = 0; - if (COMPACT_STRINGS) { // Latin1 only loop - while (sp < sl) { - int b1 = src[sp]; - if (b1 >= 0) { - dst[dp++] = (byte)b1; - sp++; - continue; - } - if ((b1 == (byte)0xc2 || b1 == (byte)0xc3) && - sp + 1 < sl) { - int b2 = src[sp + 1]; - if (!isNotContinuation(b2)) { - dst[dp++] = (byte)(((b1 << 6) ^ b2)^ - (((byte) 0xC0 << 6) ^ - ((byte) 0x80 << 0))); - sp += 2; - continue; - } - } - // anything not a latin1, including the repl - // we have to go with the utf16 - break; - } - if (sp == sl) { - if (dp != dst.length) { - dst = Arrays.copyOf(dst, dp); - } - return ret.with(dst, LATIN1); - } - } - if (dp == 0) { - dst = new byte[len << 1]; - } else { - byte[] buf = new byte[len << 1]; - StringLatin1.inflate(dst, 0, buf, 0, dp); - dst = buf; - } - while (sp < sl) { - int b1 = src[sp++]; - if (b1 >= 0) { - putChar(dst, dp++, (char) b1); - } else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) { - if (sp < sl) { - int b2 = src[sp++]; - if (isNotContinuation(b2)) { - putChar(dst, dp++, repl); - sp--; - } else { - putChar(dst, dp++, (char)(((b1 << 6) ^ b2)^ - (((byte) 0xC0 << 6) ^ - ((byte) 0x80 << 0)))); - } - continue; - } - putChar(dst, dp++, repl); - break; - } else if ((b1 >> 4) == -2) { - if (sp + 1 < sl) { - int b2 = src[sp++]; - int b3 = src[sp++]; - if (isMalformed3(b1, b2, b3)) { - putChar(dst, dp++, repl); - sp -= 3; - sp += malformedN(src, sp, 3); - } else { - char c = (char)((b1 << 12) ^ - (b2 << 6) ^ - (b3 ^ - (((byte) 0xE0 << 12) ^ - ((byte) 0x80 << 6) ^ - ((byte) 0x80 << 0)))); - putChar(dst, dp++, isSurrogate(c) ? repl : c); - } - continue; - } - if (sp < sl && isMalformed3_2(b1, src[sp])) { - putChar(dst, dp++, repl); - continue; - } - putChar(dst, dp++, repl); - break; - } else if ((b1 >> 3) == -2) { - if (sp + 2 < sl) { - int b2 = src[sp++]; - int b3 = src[sp++]; - int b4 = src[sp++]; - int uc = ((b1 << 18) ^ - (b2 << 12) ^ - (b3 << 6) ^ - (b4 ^ - (((byte) 0xF0 << 18) ^ - ((byte) 0x80 << 12) ^ - ((byte) 0x80 << 6) ^ - ((byte) 0x80 << 0)))); - if (isMalformed4(b2, b3, b4) || - !isSupplementaryCodePoint(uc)) { // shortest form check - putChar(dst, dp++, repl); - sp -= 4; - sp += malformedN(src, sp, 4); - } else { - putChar(dst, dp++, highSurrogate(uc)); - putChar(dst, dp++, lowSurrogate(uc)); - } - continue; - } - b1 &= 0xff; - if (b1 > 0xf4 || - sp < sl && isMalformed4_2(b1, src[sp] & 0xff)) { - putChar(dst, dp++, repl); - continue; - } - sp++; - putChar(dst, dp++, repl); - if (sp < sl && isMalformed4_3(src[sp])) { - continue; - } - break; - } else { - putChar(dst, dp++, repl); - } - } - if (dp != len) { - dst = Arrays.copyOf(dst, dp << 1); - } - return ret.with(dst, UTF16); - } -}
--- a/src/java.base/share/classes/java/lang/System.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/lang/System.java Wed Dec 13 10:25:38 2017 -0800 @@ -2184,6 +2184,15 @@ public Stream<ModuleLayer> layers(ClassLoader loader) { return ModuleLayer.layers(loader); } + + public String newStringUTF8NoRepl(byte[] bytes, int off, int len) { + return StringCoding.newStringUTF8NoRepl(bytes, off, len); + } + + public byte[] getBytesUTF8NoRepl(String s) { + return StringCoding.getBytesUTF8NoRepl(s); + } + }); } }
--- a/src/java.base/share/classes/java/lang/invoke/MethodType.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/lang/invoke/MethodType.java Wed Dec 13 10:25:38 2017 -0800 @@ -105,23 +105,10 @@ private @Stable String methodDescriptor; // cache for toMethodDescriptorString /** - * Check the given parameters for validity and store them into the final fields. + * Constructor that performs no copying or validation. + * Should only be called from the factory method makeImpl */ - private MethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted) { - checkRtype(rtype); - checkPtypes(ptypes); - this.rtype = rtype; - // defensively copy the array passed in by the user - this.ptypes = trusted ? ptypes : Arrays.copyOf(ptypes, ptypes.length); - } - - /** - * Construct a temporary unchecked instance of MethodType for use only as a key to the intern table. - * Does not check the given parameters for validity, and must discarded (if untrusted) or checked - * (if trusted) after it has been used as a searching key. - * The parameters are reversed for this constructor, so that it is not accidentally used. - */ - private MethodType(Class<?>[] ptypes, Class<?> rtype) { + private MethodType(Class<?> rtype, Class<?>[] ptypes) { this.rtype = rtype; this.ptypes = ptypes; } @@ -308,18 +295,21 @@ if (ptypes.length == 0) { ptypes = NO_PTYPES; trusted = true; } - MethodType primordialMT = new MethodType(ptypes, rtype); + MethodType primordialMT = new MethodType(rtype, ptypes); MethodType mt = internTable.get(primordialMT); if (mt != null) return mt; // promote the object to the Real Thing, and reprobe + MethodType.checkRtype(rtype); if (trusted) { - MethodType.checkRtype(rtype); MethodType.checkPtypes(ptypes); mt = primordialMT; } else { - mt = new MethodType(rtype, ptypes, false); + // Make defensive copy then validate + ptypes = Arrays.copyOf(ptypes, ptypes.length); + MethodType.checkPtypes(ptypes); + mt = new MethodType(rtype, ptypes); } mt.form = MethodTypeForm.findForm(mt); return internTable.add(mt);
--- a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java Wed Dec 13 10:25:38 2017 -0800 @@ -39,6 +39,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -2603,7 +2604,8 @@ * Returns a string containing the given set of modifiers and label. */ private static <M> String toString(Set<M> mods, String what) { - return (Stream.concat(mods.stream().map(e -> e.toString().toLowerCase()), + return (Stream.concat(mods.stream().map(e -> e.toString() + .toLowerCase(Locale.ROOT)), Stream.of(what))) .collect(Collectors.joining(" ")); }
--- a/src/java.base/share/classes/java/net/URLClassLoader.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/net/URLClassLoader.java Wed Dec 13 10:25:38 2017 -0800 @@ -658,8 +658,8 @@ * * @param name the resource name * @exception IOException if an I/O exception occurs - * @return an {@code Enumeration} of {@code URL}s - * If the loader is closed, the Enumeration will be empty. + * @return An {@code Enumeration} of {@code URL}s. + * If the loader is closed, the Enumeration contains no elements. */ public Enumeration<URL> findResources(final String name) throws IOException
--- a/src/java.base/share/classes/java/net/URLDecoder.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/net/URLDecoder.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,10 @@ package java.net; import java.io.*; +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; +import java.util.Objects; /** * Utility class for HTML form decoding. This class contains static methods @@ -108,7 +112,43 @@ /** * Decodes an {@code application/x-www-form-urlencoded} string using * a specific encoding scheme. - * The supplied encoding is used to determine + * + * <p> + * This method behaves the same as {@linkplain decode(String s, Charset charset)} + * except that it will {@linkplain java.nio.charset.Charset#forName look up the charset} + * using the given encoding name. + * + * @implNote This implementation will throw an {@link java.lang.IllegalArgumentException} + * when illegal strings are encountered. + * + * @param s the {@code String} to decode + * @param enc The name of a supported + * <a href="../lang/package-summary.html#charenc">character + * encoding</a>. + * @return the newly decoded {@code String} + * @throws UnsupportedEncodingException + * If character encoding needs to be consulted, but + * named character encoding is not supported + * @see URLEncoder#encode(java.lang.String, java.lang.String) + * @since 1.4 + */ + public static String decode(String s, String enc) throws UnsupportedEncodingException { + if (enc.length() == 0) { + throw new UnsupportedEncodingException ("URLDecoder: empty string enc parameter"); + } + + try { + Charset charset = Charset.forName(enc); + return decode(s, charset); + } catch (IllegalCharsetNameException | UnsupportedCharsetException e) { + throw new UnsupportedEncodingException(enc); + } + } + + /** + * Decodes an {@code application/x-www-form-urlencoded} string using + * a specific {@linkplain java.nio.charset.Charset Charset}. + * The supplied charset is used to determine * what characters are represented by any consecutive sequences of the * form "<i>{@code %xy}</i>". * <p> @@ -118,29 +158,25 @@ * UTF-8 should be used. Not doing so may introduce * incompatibilities.</em> * + * @implNote This implementation will throw an {@link java.lang.IllegalArgumentException} + * when illegal strings are encountered. + * * @param s the {@code String} to decode - * @param enc The name of a supported - * <a href="../lang/package-summary.html#charenc">character - * encoding</a>. + * @param charset the given charset * @return the newly decoded {@code String} - * @exception UnsupportedEncodingException - * If character encoding needs to be consulted, but - * named character encoding is not supported - * @see URLEncoder#encode(java.lang.String, java.lang.String) - * @since 1.4 + * @throws NullPointerException if {@code s} or {@code charset} is {@code null} + * @throws IllegalArgumentException if the implementation encounters illegal + * characters + * @see URLEncoder#encode(java.lang.String, java.nio.charset.Charset) + * @since 10 */ - public static String decode(String s, String enc) - throws UnsupportedEncodingException{ - + public static String decode(String s, Charset charset) { + Objects.requireNonNull(charset, "Charset"); boolean needToChange = false; int numChars = s.length(); StringBuilder sb = new StringBuilder(numChars > 500 ? numChars / 2 : numChars); int i = 0; - if (enc.length() == 0) { - throw new UnsupportedEncodingException ("URLDecoder: empty string enc parameter"); - } - char c; byte[] bytes = null; while (i < numChars) { @@ -173,7 +209,9 @@ (c=='%')) { int v = Integer.parseInt(s, i + 1, i + 3, 16); if (v < 0) - throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern - negative value"); + throw new IllegalArgumentException( + "URLDecoder: Illegal hex characters in escape " + + "(%) pattern - negative value"); bytes[pos++] = (byte) v; i+= 3; if (i < numChars) @@ -187,7 +225,7 @@ throw new IllegalArgumentException( "URLDecoder: Incomplete trailing escape (%) pattern"); - sb.append(new String(bytes, 0, pos, enc)); + sb.append(new String(bytes, 0, pos, charset)); } catch (NumberFormatException e) { throw new IllegalArgumentException( "URLDecoder: Illegal hex characters in escape (%) pattern - "
--- a/src/java.base/share/classes/java/net/URLEncoder.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/net/URLEncoder.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException ; import java.util.BitSet; +import java.util.Objects; import sun.security.action.GetPropertyAction; /** @@ -168,45 +169,61 @@ /** * Translates a string into {@code application/x-www-form-urlencoded} - * format using a specific encoding scheme. This method uses the - * supplied encoding scheme to obtain the bytes for unsafe - * characters. + * format using a specific encoding scheme. * <p> - * <em><strong>Note:</strong> The <a href= - * "http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars"> - * World Wide Web Consortium Recommendation</a> states that - * UTF-8 should be used. Not doing so may introduce - * incompatibilities.</em> + * This method behaves the same as {@linkplain encode(String s, Charset charset)} + * except that it will {@linkplain java.nio.charset.Charset#forName look up the charset} + * using the given encoding name. * * @param s {@code String} to be translated. * @param enc The name of a supported * <a href="../lang/package-summary.html#charenc">character * encoding</a>. * @return the translated {@code String}. - * @exception UnsupportedEncodingException + * @throws UnsupportedEncodingException * If the named encoding is not supported * @see URLDecoder#decode(java.lang.String, java.lang.String) * @since 1.4 */ public static String encode(String s, String enc) throws UnsupportedEncodingException { + if (enc == null) { + throw new NullPointerException("charsetName"); + } + + try { + Charset charset = Charset.forName(enc); + return encode(s, charset); + } catch (IllegalCharsetNameException | UnsupportedCharsetException e) { + throw new UnsupportedEncodingException(enc); + } + } + + /** + * Translates a string into {@code application/x-www-form-urlencoded} + * format using a specific {@linkplain java.nio.charset.Charset Charset}. + * This method uses the supplied charset to obtain the bytes for unsafe + * characters. + * <p> + * <em><strong>Note:</strong> The <a href= + * "http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars"> + * World Wide Web Consortium Recommendation</a> states that + * UTF-8 should be used. Not doing so may introduce incompatibilities.</em> + * + * @param s {@code String} to be translated. + * @param charset the given charset + * @return the translated {@code String}. + * @throws NullPointerException if {@code s} or {@code charset} is {@code null}. + * @see URLDecoder#decode(java.lang.String, java.nio.charset.Charset) + * @since 10 + */ + public static String encode(String s, Charset charset) { + Objects.requireNonNull(charset, "charset"); boolean needToChange = false; StringBuilder out = new StringBuilder(s.length()); - Charset charset; CharArrayWriter charArrayWriter = new CharArrayWriter(); - if (enc == null) - throw new NullPointerException("charsetName"); - - try { - charset = Charset.forName(enc); - } catch (IllegalCharsetNameException e) { - throw new UnsupportedEncodingException(enc); - } catch (UnsupportedCharsetException e) { - throw new UnsupportedEncodingException(enc); - } - for (int i = 0; i < s.length();) { int c = (int) s.charAt(i); //System.out.println("Examining character: " + c);
--- a/src/java.base/share/classes/java/net/URLStreamHandler.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/net/URLStreamHandler.java Wed Dec 13 10:25:38 2017 -0800 @@ -480,39 +480,14 @@ * @return a string representation of the {@code URL} argument. */ protected String toExternalForm(URL u) { - - // pre-compute length of StringBuffer - int len = u.getProtocol().length() + 1; - if (u.getAuthority() != null && u.getAuthority().length() > 0) - len += 2 + u.getAuthority().length(); - if (u.getPath() != null) { - len += u.getPath().length(); - } - if (u.getQuery() != null) { - len += 1 + u.getQuery().length(); - } - if (u.getRef() != null) - len += 1 + u.getRef().length(); - - StringBuilder result = new StringBuilder(len); - result.append(u.getProtocol()); - result.append(":"); - if (u.getAuthority() != null && u.getAuthority().length() > 0) { - result.append("//"); - result.append(u.getAuthority()); - } - if (u.getPath() != null) { - result.append(u.getPath()); - } - if (u.getQuery() != null) { - result.append('?'); - result.append(u.getQuery()); - } - if (u.getRef() != null) { - result.append("#"); - result.append(u.getRef()); - } - return result.toString(); + String s; + return u.getProtocol() + + ':' + + (((s = u.getAuthority()) != null && s.length() > 0) + ? "//" + s : "") + + (((s = u.getPath()) != null) ? s : "") + + (((s = u.getQuery()) != null) ? '?' + s : "") + + (((s = u.getRef()) != null) ? '#' + s : ""); } /**
--- a/src/java.base/share/classes/java/nio/channels/Channels.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/nio/channels/Channels.java Wed Dec 13 10:25:38 2017 -0800 @@ -527,7 +527,7 @@ * behaves in exactly the same way as the expression * * <pre> {@code - * Channels.newReader(ch, Charset.forName(csName).newDecoder(), -1) + * Channels.newReader(ch, Charset.forName(csName)) * } </pre> * * @param ch @@ -550,6 +550,38 @@ } /** + * Constructs a reader that decodes bytes from the given channel according + * to the given charset. + * + * <p> An invocation of this method of the form + * + * <pre> {@code + * Channels.newReader(ch, charset) + * } </pre> + * + * behaves in exactly the same way as the expression + * + * <pre> {@code + * Channels.newReader(ch, Charset.forName(csName).newDecoder(), -1) + * } </pre> + * + * <p> The reader's default action for malformed-input and unmappable-character + * errors is to {@linkplain java.nio.charset.CodingErrorAction#REPORT report} + * them. When more control over the error handling is required, the constructor + * that takes a {@linkplain java.nio.charset.CharsetDecoder} should be used. + * + * @param ch The channel from which bytes will be read + * + * @param charset The charset to be used + * + * @return A new reader + */ + public static Reader newReader(ReadableByteChannel ch, Charset charset) { + Objects.requireNonNull(charset, "charset"); + return newReader(ch, charset.newDecoder(), -1); + } + + /** * Constructs a writer that encodes characters using the given encoder and * writes the resulting bytes to the given channel. * @@ -595,7 +627,7 @@ * behaves in exactly the same way as the expression * * <pre> {@code - * Channels.newWriter(ch, Charset.forName(csName).newEncoder(), -1) + * Channels.newWriter(ch, Charset.forName(csName)) * } </pre> * * @param ch @@ -616,4 +648,38 @@ Objects.requireNonNull(csName, "csName"); return newWriter(ch, Charset.forName(csName).newEncoder(), -1); } + + /** + * Constructs a writer that encodes characters according to the given + * charset and writes the resulting bytes to the given channel. + * + * <p> An invocation of this method of the form + * + * <pre> {@code + * Channels.newWriter(ch, charset) + * } </pre> + * + * behaves in exactly the same way as the expression + * + * <pre> {@code + * Channels.newWriter(ch, Charset.forName(csName).newEncoder(), -1) + * } </pre> + * + * <p> The writer's default action for malformed-input and unmappable-character + * errors is to {@linkplain java.nio.charset.CodingErrorAction#REPORT report} + * them. When more control over the error handling is required, the constructor + * that takes a {@linkplain java.nio.charset.CharsetEncoder} should be used. + * + * @param ch + * The channel to which bytes will be written + * + * @param charset + * The charset to be used + * + * @return A new writer + */ + public static Writer newWriter(WritableByteChannel ch, Charset charset) { + Objects.requireNonNull(charset, "charset"); + return newWriter(ch, charset.newEncoder(), -1); } +}
--- a/src/java.base/share/classes/java/text/DateFormat.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/text/DateFormat.java Wed Dec 13 10:25:38 2017 -0800 @@ -97,6 +97,13 @@ * DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE); * }</pre> * </blockquote> + * + * <p>If the specified locale contains "ca" (calendar), "rg" (region override), + * and/or "tz" (timezone) <a href="../util/Locale.html#def_locale_extension">Unicode + * extensions</a>, the calendar, the country and/or the time zone for formatting + * are overridden. If both "ca" and "rg" are specified, the calendar from the "ca" + * extension supersedes the implicit one from the "rg" extension. + * * <p>You can use a DateFormat to parse also. * <blockquote> * <pre>{@code
--- a/src/java.base/share/classes/java/text/DateFormatSymbols.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/text/DateFormatSymbols.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,6 +49,7 @@ import java.util.ResourceBundle; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import sun.util.locale.provider.CalendarDataUtility; import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleServiceProviderPool; import sun.util.locale.provider.ResourceBundleBasedAdapter; @@ -82,6 +83,10 @@ * </pre> * </blockquote> * + * <p>If the locale contains "rg" (region override) + * <a href="../util/Locale.html#def_locale_extension">Unicode extension</a>, + * the symbols are overridden for the designated region. + * * <p> * <code>DateFormatSymbols</code> objects are cloneable. When you obtain * a <code>DateFormatSymbols</code> object, feel free to modify the @@ -716,15 +721,18 @@ } dfs = new DateFormatSymbols(false); + // check for region override + Locale override = CalendarDataUtility.findRegionOverride(locale); + // Initialize the fields from the ResourceBundle for locale. LocaleProviderAdapter adapter - = LocaleProviderAdapter.getAdapter(DateFormatSymbolsProvider.class, locale); + = LocaleProviderAdapter.getAdapter(DateFormatSymbolsProvider.class, override); // Avoid any potential recursions if (!(adapter instanceof ResourceBundleBasedAdapter)) { adapter = LocaleProviderAdapter.getResourceBundleBased(); } ResourceBundle resource - = ((ResourceBundleBasedAdapter)adapter).getLocaleData().getDateFormatData(locale); + = ((ResourceBundleBasedAdapter)adapter).getLocaleData().getDateFormatData(override); dfs.locale = locale; // JRE and CLDR use different keys
--- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ import java.text.spi.DecimalFormatSymbolsProvider; import java.util.Currency; import java.util.Locale; +import sun.util.locale.provider.CalendarDataUtility; import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleServiceProviderPool; import sun.util.locale.provider.ResourceBundleBasedAdapter; @@ -56,6 +57,10 @@ * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from * your <code>DecimalFormat</code> and modify it. * + * <p>If the locale contains "rg" (region override) + * <a href="../util/Locale.html#def_locale_extension">Unicode extension</a>, + * the symbols are overridden for the designated region. + * * @see java.util.Locale * @see DecimalFormat * @author Mark Davis @@ -609,13 +614,18 @@ private void initialize( Locale locale ) { this.locale = locale; + // check for region override + Locale override = locale.getUnicodeLocaleType("nu") == null ? + CalendarDataUtility.findRegionOverride(locale) : + locale; + // get resource bundle data - LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale); + LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, override); // Avoid potential recursions if (!(adapter instanceof ResourceBundleBasedAdapter)) { adapter = LocaleProviderAdapter.getResourceBundleBased(); } - Object[] data = adapter.getLocaleResources(locale).getDecimalFormatSymbolsData(); + Object[] data = adapter.getLocaleResources(override).getDecimalFormatSymbolsData(); String[] numberElements = (String[]) data[0]; decimalSeparator = numberElements[0].charAt(0);
--- a/src/java.base/share/classes/java/text/NumberFormat.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/text/NumberFormat.java Wed Dec 13 10:25:38 2017 -0800 @@ -96,7 +96,14 @@ * NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH); * }</pre> * </blockquote> - * You can also use a <code>NumberFormat</code> to parse numbers: + * + * <p>If the locale contains "nu" (numbers) and/or "rg" (region override) + * <a href="../util/Locale.html#def_locale_extension">Unicode extensions</a>, + * the decimal digits, and/or the country used for formatting are overridden. + * If both "nu" and "rg" are specified, the decimal digits from the "nu" + * extension supersedes the implicit one from the "rg" extension. + * + * <p>You can also use a {@code NumberFormat} to parse numbers: * <blockquote> * <pre>{@code * myNumber = nf.parse(myString);
--- a/src/java.base/share/classes/java/text/SimpleDateFormat.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/text/SimpleDateFormat.java Wed Dec 13 10:25:38 2017 -0800 @@ -672,7 +672,7 @@ // However, the calendar should use the current default TimeZone. // If this is not contained in the locale zone strings, then the zone // will be formatted using generic GMT+/-H:MM nomenclature. - calendar = Calendar.getInstance(TimeZone.getDefault(), loc); + calendar = Calendar.getInstance(loc); } }
--- a/src/java.base/share/classes/java/time/format/DateTimeFormatter.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatter.java Wed Dec 13 10:25:38 2017 -0800 @@ -97,6 +97,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import sun.util.locale.provider.TimeZoneNameUtility; /** * Formatter for printing and parsing date-time objects. @@ -548,7 +549,7 @@ * For example, {@code d MMM uuuu} will format 2011-12-03 as '3 Dec 2011'. * <p> * The formatter will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}. - * This can be changed using {@link DateTimeFormatter#withLocale(Locale)} on the returned formatter + * This can be changed using {@link DateTimeFormatter#withLocale(Locale)} on the returned formatter. * Alternatively use the {@link #ofPattern(String, Locale)} variant of this method. * <p> * The returned formatter has no override chronology or zone. @@ -572,7 +573,7 @@ * For example, {@code d MMM uuuu} will format 2011-12-03 as '3 Dec 2011'. * <p> * The formatter will use the specified locale. - * This can be changed using {@link DateTimeFormatter#withLocale(Locale)} on the returned formatter + * This can be changed using {@link DateTimeFormatter#withLocale(Locale)} on the returned formatter. * <p> * The returned formatter has no override chronology or zone. * It uses {@link ResolverStyle#SMART SMART} resolver style. @@ -1443,10 +1444,17 @@ * This is used to lookup any part of the formatter needing specific * localization, such as the text or localized pattern. * <p> + * The locale is stored as passed in, without further processing. + * If the locale has <a href="../../util/Locale.html#def_locale_extension"> + * Unicode extensions</a>, they may be used later in text + * processing. To set the chronology, time-zone and decimal style from + * unicode extensions, see {@link #localizedBy localizedBy()}. + * <p> * This instance is immutable and unaffected by this method call. * * @param locale the new locale, not null * @return a formatter based on this formatter with the requested locale, not null + * @see #localizedBy(Locale) */ public DateTimeFormatter withLocale(Locale locale) { if (this.locale.equals(locale)) { @@ -1455,6 +1463,52 @@ return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone); } + /** + * Returns a copy of this formatter with localized values of the locale, + * calendar, region, decimal style and/or timezone, that supercede values in + * this formatter. + * <p> + * This is used to lookup any part of the formatter needing specific + * localization, such as the text or localized pattern. If the locale contains the + * "ca" (calendar), "nu" (numbering system), "rg" (region override), and/or + * "tz" (timezone) + * <a href="../../util/Locale.html#def_locale_extension">Unicode extensions</a>, + * the chronology, numbering system and/or the zone are overridden. If both "ca" + * and "rg" are specified, the chronology from the "ca" extension supersedes the + * implicit one from the "rg" extension. Same is true for the "nu" extension. + * <p> + * Unlike the {@link #withLocale withLocale} method, the call to this method may + * produce a different formatter depending on the order of method chaining with + * other withXXXX() methods. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param locale the locale, not null + * @return a formatter based on this formatter with localized values of + * the calendar, decimal style and/or timezone, that supercede values in this + * formatter. + * @see #withLocale(Locale) + * @since 10 + */ + public DateTimeFormatter localizedBy(Locale locale) { + if (this.locale.equals(locale)) { + return this; + } + + // Check for decimalStyle/chronology/timezone in locale object + Chronology c = locale.getUnicodeLocaleType("ca") != null ? + Chronology.ofLocale(locale) : chrono; + DecimalStyle ds = locale.getUnicodeLocaleType("nu") != null ? + DecimalStyle.of(locale) : decimalStyle; + String tzType = locale.getUnicodeLocaleType("tz"); + ZoneId z = tzType != null ? + TimeZoneNameUtility.convertLDMLShortID(tzType) + .map(ZoneId::of) + .orElse(zone) : + zone; + return new DateTimeFormatter(printerParser, locale, ds, resolverStyle, resolverFields, c, z); + } + //----------------------------------------------------------------------- /** * Gets the DecimalStyle to be used during formatting.
--- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,6 +120,7 @@ import java.util.concurrent.ConcurrentMap; import sun.text.spi.JavaTimeDateTimePatternProvider; +import sun.util.locale.provider.CalendarDataUtility; import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleResources; import sun.util.locale.provider.TimeZoneNameUtility; @@ -198,6 +199,10 @@ * Gets the formatting pattern for date and time styles for a locale and chronology. * The locale and chronology are used to lookup the locale specific format * for the requested dateStyle and/or timeStyle. + * <p> + * If the locale contains the "rg" (region override) + * <a href="../../util/Locale.html#def_locale_extension">Unicode extensions</a>, + * the formatting pattern is overridden with the one appropriate for the region. * * @param dateStyle the FormatStyle for the date, null for time-only pattern * @param timeStyle the FormatStyle for the time, null for date-only pattern @@ -216,7 +221,8 @@ LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(JavaTimeDateTimePatternProvider.class, locale); JavaTimeDateTimePatternProvider provider = adapter.getJavaTimeDateTimePatternProvider(); String pattern = provider.getJavaTimeDateTimePattern(convertStyle(timeStyle), - convertStyle(dateStyle), chrono.getCalendarType(), locale); + convertStyle(dateStyle), chrono.getCalendarType(), + CalendarDataUtility.findRegionOverride(locale)); return pattern; }
--- a/src/java.base/share/classes/java/time/format/DateTimeTextProvider.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/time/format/DateTimeTextProvider.java Wed Dec 13 10:25:38 2017 -0800 @@ -510,7 +510,8 @@ @SuppressWarnings("unchecked") static <T> T getLocalizedResource(String key, Locale locale) { LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased() - .getLocaleResources(locale); + .getLocaleResources( + CalendarDataUtility.findRegionOverride(locale)); ResourceBundle rb = lr.getJavaTimeFormatData(); return rb.containsKey(key) ? (T) rb.getObject(key) : null; }
--- a/src/java.base/share/classes/java/time/format/DecimalStyle.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/time/format/DecimalStyle.java Wed Dec 13 10:25:38 2017 -0800 @@ -147,6 +147,11 @@ * Obtains the DecimalStyle for the specified locale. * <p> * This method provides access to locale sensitive decimal style symbols. + * If the locale contains "nu" (Numbering System) and/or "rg" + * (Region Override) <a href="../../util/Locale.html#def_locale_extension"> + * Unicode extensions</a>, returned instance will reflect the values specified with + * those extensions. If both "nu" and "rg" are specified, the value from + * the "nu" extension supersedes the implicit one from the "rg" extension. * * @param locale the locale, not null * @return the decimal style, not null
--- a/src/java.base/share/classes/java/time/temporal/ChronoField.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/time/temporal/ChronoField.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,6 +79,7 @@ import java.util.Locale; import java.util.Objects; import java.util.ResourceBundle; +import sun.util.locale.provider.CalendarDataUtility; import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleResources; @@ -632,7 +633,9 @@ } LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased() - .getLocaleResources(locale); + .getLocaleResources( + CalendarDataUtility + .findRegionOverride(locale)); ResourceBundle rb = lr.getJavaTimeFormatData(); String key = "field." + displayNameKey; return rb.containsKey(key) ? rb.getString(key) : name;
--- a/src/java.base/share/classes/java/time/temporal/IsoFields.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/time/temporal/IsoFields.java Wed Dec 13 10:25:38 2017 -0800 @@ -81,6 +81,7 @@ import java.util.Objects; import java.util.ResourceBundle; +import sun.util.locale.provider.CalendarDataUtility; import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleResources; @@ -430,7 +431,9 @@ public String getDisplayName(Locale locale) { Objects.requireNonNull(locale, "locale"); LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased() - .getLocaleResources(locale); + .getLocaleResources( + CalendarDataUtility + .findRegionOverride(locale)); ResourceBundle rb = lr.getJavaTimeFormatData(); return rb.containsKey("field.week") ? rb.getString("field.week") : toString(); }
--- a/src/java.base/share/classes/java/time/temporal/WeekFields.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/time/temporal/WeekFields.java Wed Dec 13 10:25:38 2017 -0800 @@ -286,13 +286,17 @@ * Obtains an instance of {@code WeekFields} appropriate for a locale. * <p> * This will look up appropriate values from the provider of localization data. + * If the locale contains "fw" (First day of week) and/or "rg" + * (Region Override) <a href="../../util/Locale.html#def_locale_extension"> + * Unicode extensions</a>, returned instance will reflect the values specified with + * those extensions. If both "fw" and "rg" are specified, the value from + * the "fw" extension supersedes the implicit one from the "rg" extension. * * @param locale the locale to use, not null * @return the week-definition, not null */ public static WeekFields of(Locale locale) { Objects.requireNonNull(locale, "locale"); - locale = new Locale(locale.getLanguage(), locale.getCountry()); // elminate variants int calDow = CalendarDataUtility.retrieveFirstDayOfWeek(locale); DayOfWeek dow = DayOfWeek.SUNDAY.plus(calDow - 1); @@ -1041,7 +1045,8 @@ Objects.requireNonNull(locale, "locale"); if (rangeUnit == YEARS) { // only have values for week-of-year LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased() - .getLocaleResources(locale); + .getLocaleResources( + CalendarDataUtility.findRegionOverride(locale)); ResourceBundle rb = lr.getJavaTimeFormatData(); return rb.containsKey("field.week") ? rb.getString("field.week") : name; }
--- a/src/java.base/share/classes/java/util/Calendar.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/Calendar.java Wed Dec 13 10:25:38 2017 -0800 @@ -58,6 +58,7 @@ import sun.util.calendar.ZoneInfo; import sun.util.locale.provider.CalendarDataUtility; import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.TimeZoneNameUtility; import sun.util.spi.CalendarProvider; /** @@ -128,9 +129,14 @@ * * <code>Calendar</code> defines a locale-specific seven day week using two * parameters: the first day of the week and the minimal days in first week - * (from 1 to 7). These numbers are taken from the locale resource data when a - * <code>Calendar</code> is constructed. They may also be specified explicitly - * through the methods for setting their values. + * (from 1 to 7). These numbers are taken from the locale resource data or the + * locale itself when a {@code Calendar} is constructed. If the designated + * locale contains "fw" and/or "rg" <a href="./Locale.html#def_locale_extension"> + * Unicode extensions</a>, the first day of the week will be obtained according to + * those extensions. If both "fw" and "rg" are specified, the value from the "fw" + * extension supersedes the implicit one from the "rg" extension. + * They may also be specified explicitly through the methods for setting their + * values. * * <p>When setting or getting the <code>WEEK_OF_MONTH</code> or * <code>WEEK_OF_YEAR</code> fields, <code>Calendar</code> must determine the @@ -1444,6 +1450,11 @@ * * <p>The default values are used for locale and time zone if these * parameters haven't been given explicitly. + * <p> + * If the locale contains the time zone with "tz" + * <a href="Locale.html#def_locale_extension">Unicode extension</a>, + * and time zone hasn't been given explicitly, time zone in the locale + * is used. * * <p>Any out of range field values are either normalized in lenient * mode or detected as an invalid value in non-lenient mode. @@ -1463,7 +1474,7 @@ locale = Locale.getDefault(); } if (zone == null) { - zone = TimeZone.getDefault(); + zone = defaultTimeZone(locale); } Calendar cal; if (type == null) { @@ -1605,12 +1616,17 @@ * <code>Calendar</code> returned is based on the current time * in the default time zone with the default * {@link Locale.Category#FORMAT FORMAT} locale. + * <p> + * If the locale contains the time zone with "tz" + * <a href="Locale.html#def_locale_extension">Unicode extension</a>, + * that time zone is used instead. * * @return a Calendar. */ public static Calendar getInstance() { - return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT)); + Locale aLocale = Locale.getDefault(Locale.Category.FORMAT); + return createCalendar(defaultTimeZone(aLocale), aLocale); } /** @@ -1631,13 +1647,17 @@ * Gets a calendar using the default time zone and specified locale. * The <code>Calendar</code> returned is based on the current time * in the default time zone with the given locale. + * <p> + * If the locale contains the time zone with "tz" + * <a href="Locale.html#def_locale_extension">Unicode extension</a>, + * that time zone is used instead. * * @param aLocale the locale for the week data * @return a Calendar. */ public static Calendar getInstance(Locale aLocale) { - return createCalendar(TimeZone.getDefault(), aLocale); + return createCalendar(defaultTimeZone(aLocale), aLocale); } /** @@ -1655,6 +1675,16 @@ return createCalendar(zone, aLocale); } + private static TimeZone defaultTimeZone(Locale l) { + TimeZone defaultTZ = TimeZone.getDefault(); + String shortTZID = l.getUnicodeLocaleType("tz"); + return shortTZID != null ? + TimeZoneNameUtility.convertLDMLShortID(shortTZID) + .map(TimeZone::getTimeZone) + .orElse(defaultTZ) : + defaultTZ; + } + private static Calendar createCalendar(TimeZone zone, Locale aLocale) {
--- a/src/java.base/share/classes/java/util/Collections.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/Collections.java Wed Dec 13 10:25:38 2017 -0800 @@ -24,9 +24,10 @@ */ package java.util; + +import java.io.IOException; +import java.io.ObjectOutputStream; import java.io.Serializable; -import java.io.ObjectOutputStream; -import java.io.IOException; import java.lang.reflect.Array; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -5164,14 +5165,19 @@ * specified comparator. * @since 1.5 */ + @SuppressWarnings("unchecked") public static <T> Comparator<T> reverseOrder(Comparator<T> cmp) { - if (cmp == null) - return reverseOrder(); - - if (cmp instanceof ReverseComparator2) - return ((ReverseComparator2<T>)cmp).cmp; - - return new ReverseComparator2<>(cmp); + if (cmp == null) { + return (Comparator<T>) ReverseComparator.REVERSE_ORDER; + } else if (cmp == ReverseComparator.REVERSE_ORDER) { + return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE; + } else if (cmp == Comparators.NaturalOrderComparator.INSTANCE) { + return (Comparator<T>) ReverseComparator.REVERSE_ORDER; + } else if (cmp instanceof ReverseComparator2) { + return ((ReverseComparator2<T>) cmp).cmp; + } else { + return new ReverseComparator2<>(cmp); + } } /**
--- a/src/java.base/share/classes/java/util/Currency.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/Currency.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileReader; import java.io.InputStream; import java.io.IOException; @@ -42,6 +41,7 @@ import java.util.regex.Pattern; import java.util.regex.Matcher; import java.util.spi.CurrencyNameProvider; +import sun.util.locale.provider.CalendarDataUtility; import sun.util.locale.provider.LocaleServiceProviderPool; import sun.util.logging.PlatformLogger; @@ -348,6 +348,13 @@ * until December 31, 2001, and the Euro from January 1, 2002, local time * of the respective countries. * <p> + * If the specified {@code locale} contains "cu" and/or "rg" + * <a href="./Locale.html#def_locale_extension">Unicode extensions</a>, + * the instance returned from this method reflects + * the values specified with those extensions. If both "cu" and "rg" are + * specified, the currency from the "cu" extension supersedes the implicit one + * from the "rg" extension. + * <p> * The method returns <code>null</code> for territories that don't * have a currency, such as Antarctica. * @@ -361,12 +368,19 @@ * is not a supported ISO 3166 country code. */ public static Currency getInstance(Locale locale) { - String country = locale.getCountry(); - if (country == null) { - throw new NullPointerException(); + // check for locale overrides + String override = locale.getUnicodeLocaleType("cu"); + if (override != null) { + try { + return getInstance(override.toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException iae) { + // override currency is invalid. Fall through. + } } - if (country.length() != 2) { + String country = CalendarDataUtility.findRegionOverride(locale).getCountry(); + + if (country == null || !country.matches("^[a-zA-Z]{2}$")) { throw new IllegalArgumentException(); } @@ -482,6 +496,12 @@ * locale is the US, while for other locales it may be "US$". If no * symbol can be determined, the ISO 4217 currency code is returned. * <p> + * If the default {@link Locale.Category#DISPLAY DISPLAY} locale + * contains "rg" (region override) + * <a href="./Locale.html#def_locale_extension">Unicode extension</a>, + * the symbol returned from this method reflects + * the value specified with that extension. + * <p> * This is equivalent to calling * {@link #getSymbol(Locale) * getSymbol(Locale.getDefault(Locale.Category.DISPLAY))}. @@ -498,6 +518,11 @@ * For example, for the US Dollar, the symbol is "$" if the specified * locale is the US, while for other locales it may be "US$". If no * symbol can be determined, the ISO 4217 currency code is returned. + * <p> + * If the specified {@code locale} contains "rg" (region override) + * <a href="./Locale.html#def_locale_extension">Unicode extension</a>, + * the symbol returned from this method reflects + * the value specified with that extension. * * @param locale the locale for which a display name for this currency is * needed @@ -507,6 +532,7 @@ public String getSymbol(Locale locale) { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(CurrencyNameProvider.class); + locale = CalendarDataUtility.findRegionOverride(locale); String symbol = pool.getLocalizedObject( CurrencyNameGetter.INSTANCE, locale, currencyCode, SYMBOL);
--- a/src/java.base/share/classes/java/util/Formatter.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/Formatter.java Wed Dec 13 10:25:38 2017 -0800 @@ -2137,6 +2137,39 @@ } /** + * Constructs a new formatter with the specified file name, charset, and + * locale. + * + * @param fileName + * The name of the file to use as the destination of this + * formatter. If the file exists then it will be truncated to + * zero size; otherwise, a new file will be created. The output + * will be written to the file and is buffered. + * + * @param charset + * A {@linkplain java.nio.charset.Charset charset} + * + * @param l + * The {@linkplain java.util.Locale locale} to apply during + * formatting. If {@code l} is {@code null} then no localization + * is applied. + * + * @throws IOException + * if an I/O error occurs while opening or creating the file + * + * @throws SecurityException + * If a security manager is present and {@link + * SecurityManager#checkWrite checkWrite(fileName)} denies write + * access to the file + * + * @throws NullPointerException + * if {@code fileName} or {@code charset} is {@code null}. + */ + public Formatter(String fileName, Charset charset, Locale l) throws IOException { + this(Objects.requireNonNull(charset, "charset"), l, new File(fileName)); + } + + /** * Constructs a new formatter with the specified file. * * <p> The charset used is the {@linkplain @@ -2248,6 +2281,40 @@ } /** + * Constructs a new formatter with the specified file, charset, and + * locale. + * + * @param file + * The file to use as the destination of this formatter. If the + * file exists then it will be truncated to zero size; otherwise, + * a new file will be created. The output will be written to the + * file and is buffered. + * + * @param charset + * A {@linkplain java.nio.charset.Charset charset} + * + * @param l + * The {@linkplain java.util.Locale locale} to apply during + * formatting. If {@code l} is {@code null} then no localization + * is applied. + * + * @throws IOException + * if an I/O error occurs while opening or creating the file + * + * @throws SecurityException + * If a security manager is present and {@link + * SecurityManager#checkWrite checkWrite(file.getPath())} denies + * write access to the file + * + * @throws NullPointerException + * if {@code file} or {@code charset} is {@code null}. + */ + public Formatter(File file, Charset charset, Locale l) throws IOException { + this(Objects.requireNonNull(charset, "charset"), l, file); + } + + + /** * Constructs a new formatter with the specified print stream. * * <p> The locale used is the {@linkplain @@ -2340,6 +2407,29 @@ this(l, new BufferedWriter(new OutputStreamWriter(os, csn))); } + /** + * Constructs a new formatter with the specified output stream, charset, + * and locale. + * + * @param os + * The output stream to use as the destination of this formatter. + * The output will be buffered. + * + * @param charset + * A {@linkplain java.nio.charset.Charset charset} + * + * @param l + * The {@linkplain java.util.Locale locale} to apply during + * formatting. If {@code l} is {@code null} then no localization + * is applied. + * + * @throws NullPointerException + * if {@code os} or {@code charset} is {@code null}. + */ + public Formatter(OutputStream os, Charset charset, Locale l) { + this(l, new BufferedWriter(new OutputStreamWriter(os, charset))); + } + private static char getZero(Locale l) { if ((l != null) && !l.equals(Locale.US)) { DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
--- a/src/java.base/share/classes/java/util/Locale.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/Locale.java Wed Dec 13 10:25:38 2017 -0800 @@ -48,6 +48,7 @@ import java.text.MessageFormat; import java.util.concurrent.ConcurrentHashMap; import java.util.spi.LocaleNameProvider; +import java.util.stream.Collectors; import sun.security.action.GetPropertyAction; import sun.util.locale.BaseLocale; @@ -62,6 +63,7 @@ import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleResources; import sun.util.locale.provider.LocaleServiceProviderPool; +import sun.util.locale.provider.TimeZoneNameUtility; /** * A <code>Locale</code> object represents a specific geographical, political, @@ -665,10 +667,12 @@ /** * Display types for retrieving localized names from the name providers. */ - private static final int DISPLAY_LANGUAGE = 0; - private static final int DISPLAY_COUNTRY = 1; - private static final int DISPLAY_VARIANT = 2; - private static final int DISPLAY_SCRIPT = 3; + private static final int DISPLAY_LANGUAGE = 0; + private static final int DISPLAY_COUNTRY = 1; + private static final int DISPLAY_VARIANT = 2; + private static final int DISPLAY_SCRIPT = 3; + private static final int DISPLAY_UEXT_KEY = 4; + private static final int DISPLAY_UEXT_TYPE = 5; /** * Private constructor used by getInstance method @@ -942,11 +946,14 @@ variant = props.getProperty("user.variant", ""); } - return getInstance(language, script, country, variant, null); + return getInstance(language, script, country, variant, + getDefaultExtensions(props.getProperty("user.extensions", "")) + .orElse(null)); } private static Locale initDefault(Locale.Category category) { Properties props = GetPropertyAction.privilegedGetProperties(); + return getInstance( props.getProperty(category.languageKey, defaultLocale.getLanguage()), @@ -956,7 +963,22 @@ defaultLocale.getCountry()), props.getProperty(category.variantKey, defaultLocale.getVariant()), - null); + getDefaultExtensions(props.getProperty(category.extensionsKey, "")) + .orElse(defaultLocale.getLocaleExtensions())); + } + + private static Optional<LocaleExtensions> getDefaultExtensions(String extensionsProp) { + LocaleExtensions exts = null; + + try { + exts = new InternalLocaleBuilder() + .setExtensions(extensionsProp) + .getLocaleExtensions(); + } catch (LocaleSyntaxException e) { + // just ignore this incorrect property + } + + return Optional.ofNullable(exts); } /** @@ -1771,7 +1793,7 @@ * @exception NullPointerException if <code>inLocale</code> is <code>null</code> */ public String getDisplayLanguage(Locale inLocale) { - return getDisplayString(baseLocale.getLanguage(), inLocale, DISPLAY_LANGUAGE); + return getDisplayString(baseLocale.getLanguage(), null, inLocale, DISPLAY_LANGUAGE); } /** @@ -1801,7 +1823,7 @@ * @since 1.7 */ public String getDisplayScript(Locale inLocale) { - return getDisplayString(baseLocale.getScript(), inLocale, DISPLAY_SCRIPT); + return getDisplayString(baseLocale.getScript(), null, inLocale, DISPLAY_SCRIPT); } /** @@ -1844,29 +1866,24 @@ * @exception NullPointerException if <code>inLocale</code> is <code>null</code> */ public String getDisplayCountry(Locale inLocale) { - return getDisplayString(baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY); + return getDisplayString(baseLocale.getRegion(), null, inLocale, DISPLAY_COUNTRY); } - private String getDisplayString(String code, Locale inLocale, int type) { - if (code.length() == 0) { + private String getDisplayString(String code, String cat, Locale inLocale, int type) { + Objects.requireNonNull(inLocale); + Objects.requireNonNull(code); + + if (code.isEmpty()) { return ""; } - if (inLocale == null) { - throw new NullPointerException(); - } - LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(LocaleNameProvider.class); - String key = (type == DISPLAY_VARIANT ? "%%"+code : code); + String rbKey = (type == DISPLAY_VARIANT ? "%%"+code : code); String result = pool.getLocalizedObject( LocaleNameGetter.INSTANCE, - inLocale, key, type, code); - if (result != null) { - return result; - } - - return code; + inLocale, rbKey, type, code, cat); + return result != null ? result : code; } /** @@ -1894,29 +1911,31 @@ if (baseLocale.getVariant().length() == 0) return ""; - LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale); + LocaleResources lr = LocaleProviderAdapter + .getResourceBundleBased() + .getLocaleResources(inLocale); String names[] = getDisplayVariantArray(inLocale); // Get the localized patterns for formatting a list, and use // them to format the list. return formatList(names, - lr.getLocaleName("ListPattern"), lr.getLocaleName("ListCompositionPattern")); } /** * Returns a name for the locale that is appropriate for display to the * user. This will be the values returned by getDisplayLanguage(), - * getDisplayScript(), getDisplayCountry(), and getDisplayVariant() assembled - * into a single string. The non-empty values are used in order, - * with the second and subsequent names in parentheses. For example: + * getDisplayScript(), getDisplayCountry(), getDisplayVariant() and + * optional <a href="./Locale.html#def_locale_extension">Unicode extensions</a> + * assembled into a single string. The non-empty values are used in order, with + * the second and subsequent names in parentheses. For example: * <blockquote> - * language (script, country, variant)<br> - * language (country)<br> - * language (variant)<br> - * script (country)<br> - * country<br> + * language (script, country, variant(, extension)*)<br> + * language (country(, extension)*)<br> + * language (variant(, extension)*)<br> + * script (country(, extension)*)<br> + * country (extension)*<br> * </blockquote> * depending on which fields are specified in the locale. If the * language, script, country, and variant fields are all empty, @@ -1931,16 +1950,17 @@ /** * Returns a name for the locale that is appropriate for display * to the user. This will be the values returned by - * getDisplayLanguage(), getDisplayScript(),getDisplayCountry(), - * and getDisplayVariant() assembled into a single string. - * The non-empty values are used in order, - * with the second and subsequent names in parentheses. For example: + * getDisplayLanguage(), getDisplayScript(),getDisplayCountry() + * getDisplayVariant(), and optional <a href="./Locale.html#def_locale_extension"> + * Unicode extensions</a> assembled into a single string. The non-empty + * values are used in order, with the second and subsequent names in + * parentheses. For example: * <blockquote> - * language (script, country, variant)<br> - * language (country)<br> - * language (variant)<br> - * script (country)<br> - * country<br> + * language (script, country, variant(, extension)*)<br> + * language (country(, extension)*)<br> + * language (variant(, extension)*)<br> + * script (country(, extension)*)<br> + * country (extension)*<br> * </blockquote> * depending on which fields are specified in the locale. If the * language, script, country, and variant fields are all empty, @@ -1951,7 +1971,9 @@ * @throws NullPointerException if <code>inLocale</code> is <code>null</code> */ public String getDisplayName(Locale inLocale) { - LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale); + LocaleResources lr = LocaleProviderAdapter + .getResourceBundleBased() + .getLocaleResources(inLocale); String languageName = getDisplayLanguage(inLocale); String scriptName = getDisplayScript(inLocale); @@ -1960,7 +1982,6 @@ // Get the localized patterns for formatting a display name. String displayNamePattern = lr.getLocaleName("DisplayNamePattern"); - String listPattern = lr.getLocaleName("ListPattern"); String listCompositionPattern = lr.getLocaleName("ListCompositionPattern"); // The display name consists of a main name, followed by qualifiers. @@ -1977,7 +1998,7 @@ if (variantNames.length == 0) { return ""; } else { - return formatList(variantNames, listPattern, listCompositionPattern); + return formatList(variantNames, listCompositionPattern); } } ArrayList<String> names = new ArrayList<>(4); @@ -1994,6 +2015,16 @@ names.addAll(Arrays.asList(variantNames)); } + // add Unicode extensions + if (localeExtensions != null) { + localeExtensions.getUnicodeLocaleAttributes().stream() + .map(key -> getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY)) + .forEach(names::add); + localeExtensions.getUnicodeLocaleKeys().stream() + .map(key -> getDisplayKeyTypeExtensionString(key, lr, inLocale)) + .forEach(names::add); + } + // The first one in the main name mainName = names.get(0); @@ -2014,7 +2045,7 @@ // list case, but this is more efficient, and we want it to be // efficient since all the language-only locales will not have any // qualifiers. - qualifierNames.length != 0 ? formatList(qualifierNames, listPattern, listCompositionPattern) : null + qualifierNames.length != 0 ? formatList(qualifierNames, listCompositionPattern) : null }; if (displayNamePattern != null) { @@ -2121,74 +2152,78 @@ // For each variant token, lookup the display name. If // not found, use the variant name itself. for (int i=0; i<names.length; ++i) { - names[i] = getDisplayString(tokenizer.nextToken(), + names[i] = getDisplayString(tokenizer.nextToken(), null, inLocale, DISPLAY_VARIANT); } return names; } + private String getDisplayKeyTypeExtensionString(String key, LocaleResources lr, Locale inLocale) { + String type = localeExtensions.getUnicodeLocaleType(key); + String ret = getDisplayString(type, key, inLocale, DISPLAY_UEXT_TYPE); + + if (ret == null || ret.equals(type)) { + // no localization for this type. try combining key/type separately + String displayType = type; + switch (key) { + case "cu": + displayType = lr.getCurrencyName(type.toLowerCase(Locale.ROOT)); + break; + case "rg": + if (type != null && + // UN M.49 code should not be allowed here + type.matches("^[a-zA-Z]{2}[zZ]{4}$")) { + displayType = lr.getLocaleName(type.substring(0, 2).toUpperCase(Locale.ROOT)); + } + break; + case "tz": + displayType = TimeZoneNameUtility.retrieveGenericDisplayName( + TimeZoneNameUtility.convertLDMLShortID(type).orElse(type), + TimeZone.LONG, inLocale); + break; + } + ret = MessageFormat.format(lr.getLocaleName("ListKeyTypePattern"), + getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY), + Optional.ofNullable(displayType).orElse(type)); + } + + return ret; + } + /** * Format a list using given pattern strings. * If either of the patterns is null, then a the list is * formatted by concatenation with the delimiter ','. * @param stringList the list of strings to be formatted. - * @param listPattern should create a MessageFormat taking 0-3 arguments * and formatting them into a list. - * @param listCompositionPattern should take 2 arguments - * and is used by composeList. + * @param pattern should take 2 arguments for reduction * @return a string representing the list. */ - private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) { + private static String formatList(String[] stringList, String pattern) { // If we have no list patterns, compose the list in a simple, // non-localized way. - if (listPattern == null || listCompositionPattern == null) { - StringJoiner sj = new StringJoiner(","); - for (int i = 0; i < stringList.length; ++i) { - sj.add(stringList[i]); - } - return sj.toString(); + if (pattern == null) { + return Arrays.stream(stringList).collect(Collectors.joining(",")); } - // Compose the list down to three elements if necessary - if (stringList.length > 3) { - MessageFormat format = new MessageFormat(listCompositionPattern); - stringList = composeList(format, stringList); + switch (stringList.length) { + case 0: + return ""; + case 1: + return stringList[0]; + default: + return Arrays.stream(stringList).reduce("", + (s1, s2) -> { + if (s1.equals("")) { + return s2; + } + if (s2.equals("")) { + return s1; + } + return MessageFormat.format(pattern, s1, s2); + }); } - - // Rebuild the argument list with the list length as the first element - Object[] args = new Object[stringList.length + 1]; - System.arraycopy(stringList, 0, args, 1, stringList.length); - args[0] = stringList.length; - - // Format it using the pattern in the resource - MessageFormat format = new MessageFormat(listPattern); - return format.format(args); - } - - /** - * Given a list of strings, return a list shortened to three elements. - * Shorten it by applying the given format to the first two elements - * recursively. - * @param format a format which takes two arguments - * @param list a list of strings - * @return if the list is three elements or shorter, the same list; - * otherwise, a new list of three elements. - */ - private static String[] composeList(MessageFormat format, String[] list) { - if (list.length <= 3) return list; - - // Use the given format to compose the first two elements into one - String[] listItems = { list[0], list[1] }; - String newItem = format.format(listItems); - - // Form a new list one element shorter - String[] newList = new String[list.length-1]; - System.arraycopy(list, 2, newList, 1, newList.length-1); - newList[0] = newItem; - - // Recurse - return composeList(format, newList); } // Duplicate of sun.util.locale.UnicodeLocaleExtension.isKey in order to @@ -2345,9 +2380,10 @@ Locale locale, String key, Object... params) { - assert params.length == 2; + assert params.length == 3; int type = (Integer)params[0]; String code = (String)params[1]; + String cat = (String)params[2]; switch(type) { case DISPLAY_LANGUAGE: @@ -2358,6 +2394,10 @@ return localeNameProvider.getDisplayVariant(code, locale); case DISPLAY_SCRIPT: return localeNameProvider.getDisplayScript(code, locale); + case DISPLAY_UEXT_KEY: + return localeNameProvider.getDisplayUnicodeExtensionKey(code, locale); + case DISPLAY_UEXT_TYPE: + return localeNameProvider.getDisplayUnicodeExtensionType(code, cat, locale); default: assert false; // shouldn't happen } @@ -2384,7 +2424,8 @@ DISPLAY("user.language.display", "user.script.display", "user.country.display", - "user.variant.display"), + "user.variant.display", + "user.extensions.display"), /** * Category used to represent the default locale for @@ -2393,19 +2434,23 @@ FORMAT("user.language.format", "user.script.format", "user.country.format", - "user.variant.format"); + "user.variant.format", + "user.extensions.format"); - Category(String languageKey, String scriptKey, String countryKey, String variantKey) { + Category(String languageKey, String scriptKey, String countryKey, + String variantKey, String extensionsKey) { this.languageKey = languageKey; this.scriptKey = scriptKey; this.countryKey = countryKey; this.variantKey = variantKey; + this.extensionsKey = extensionsKey; } final String languageKey; final String scriptKey; final String countryKey; final String variantKey; + final String extensionsKey; } /**
--- a/src/java.base/share/classes/java/util/Properties.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/Properties.java Wed Dec 13 10:25:38 2017 -0800 @@ -37,6 +37,10 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.StreamCorruptedException; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -997,6 +1001,11 @@ * * <p>The specified stream remains open after this method returns. * + * <p>This method behaves the same as + * {@linkplain #storeToXML(OutputStream os, String comment, Charset charset)} + * except that it will {@linkplain java.nio.charset.Charset#forName look up the charset} + * using the given encoding name. + * * @param os the output stream on which to emit the XML document. * @param comment a description of the property list, or {@code null} * if no comment is desired. @@ -1011,20 +1020,67 @@ * @throws NullPointerException if {@code os} is {@code null}, * or if {@code encoding} is {@code null}. * @throws ClassCastException if this {@code Properties} object - * contains any keys or values that are not - * {@code Strings}. + * contains any keys or values that are not {@code Strings}. * @see #loadFromXML(InputStream) * @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character * Encoding in Entities</a> * @since 1.5 */ public void storeToXML(OutputStream os, String comment, String encoding) - throws IOException - { + throws IOException { Objects.requireNonNull(os); Objects.requireNonNull(encoding); + + try { + Charset charset = Charset.forName(encoding); + storeToXML(os, comment, charset); + } catch (IllegalCharsetNameException | UnsupportedCharsetException e) { + throw new UnsupportedEncodingException(encoding); + } + } + + /** + * Emits an XML document representing all of the properties contained + * in this table, using the specified encoding. + * + * <p>The XML document will have the following DOCTYPE declaration: + * <pre> + * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> + * </pre> + * + * <p>If the specified comment is {@code null} then no comment + * will be stored in the document. + * + * <p> An implementation is required to support writing of XML documents + * that use the "{@code UTF-8}" or "{@code UTF-16}" encoding. An + * implementation may support additional encodings. + * + * <p> Unmappable characters for the specified charset will be encoded as + * numeric character references. + * + * <p>The specified stream remains open after this method returns. + * + * @param os the output stream on which to emit the XML document. + * @param comment a description of the property list, or {@code null} + * if no comment is desired. + * @param charset the charset + * + * @throws IOException if writing to the specified output stream + * results in an {@code IOException}. + * @throws NullPointerException if {@code os} or {@code charset} is {@code null}. + * @throws ClassCastException if this {@code Properties} object + * contains any keys or values that are not {@code Strings}. + * @see #loadFromXML(InputStream) + * @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character + * Encoding in Entities</a> + * @since 10 + */ + public void storeToXML(OutputStream os, String comment, Charset charset) + throws IOException { + Objects.requireNonNull(os, "OutputStream"); + Objects.requireNonNull(charset, "Charset"); PropertiesDefaultHandler handler = new PropertiesDefaultHandler(); - handler.store(this, os, comment, encoding); + handler.store(this, os, comment, charset); } /**
--- a/src/java.base/share/classes/java/util/Scanner.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/Scanner.java Wed Dec 13 10:25:38 2017 -0800 @@ -33,10 +33,13 @@ import java.nio.file.Path; import java.nio.file.Files; import java.text.*; +import java.text.spi.NumberFormatProvider; import java.util.function.Consumer; import java.util.regex.*; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; /** * A simple text scanner which can parse primitive types and strings using @@ -575,7 +578,21 @@ * does not exist */ public Scanner(InputStream source, String charsetName) { - this(makeReadable(Objects.requireNonNull(source, "source"), toCharset(charsetName)), + this(source, toCharset(charsetName)); + } + + /** + * Constructs a new {@code Scanner} that produces values scanned + * from the specified input stream. Bytes from the stream are converted + * into characters using the specified charset. + * + * @param source an input stream to be scanned + * @param charset the charset used to convert bytes from the file + * into characters to be scanned + * @since 10 + */ + public Scanner(InputStream source, Charset charset) { + this(makeReadable(Objects.requireNonNull(source, "source"), charset), WHITESPACE_PATTERN); } @@ -594,7 +611,18 @@ } } + /* + * This method is added so that null-check on charset can be performed before + * creating InputStream as an existing test required it. + */ + private static Readable makeReadable(Path source, Charset charset) + throws IOException { + Objects.requireNonNull(charset, "charset"); + return makeReadable(Files.newInputStream(source), charset); + } + private static Readable makeReadable(InputStream source, Charset charset) { + Objects.requireNonNull(charset, "charset"); return new InputStreamReader(source, charset); } @@ -629,6 +657,22 @@ this(Objects.requireNonNull(source), toDecoder(charsetName)); } + /** + * Constructs a new {@code Scanner} that produces values scanned + * from the specified file. Bytes from the file are converted into + * characters using the specified charset. + * + * @param source A file to be scanned + * @param charset The charset used to convert bytes from the file + * into characters to be scanned + * @throws IOException + * if an I/O error occurs opening the source + * @since 10 + */ + public Scanner(File source, Charset charset) throws IOException { + this(Objects.requireNonNull(source), charset.newDecoder()); + } + private Scanner(File source, CharsetDecoder dec) throws FileNotFoundException { @@ -649,6 +693,12 @@ return Channels.newReader(source, dec, -1); } + private static Readable makeReadable(ReadableByteChannel source, + Charset charset) { + Objects.requireNonNull(charset, "charset"); + return Channels.newReader(source, charset); + } + /** * Constructs a new {@code Scanner} that produces values scanned * from the specified file. Bytes from the file are converted into @@ -688,8 +738,22 @@ this(Objects.requireNonNull(source), toCharset(charsetName)); } - private Scanner(Path source, Charset charset) throws IOException { - this(makeReadable(Files.newInputStream(source), charset)); + /** + * Constructs a new {@code Scanner} that produces values scanned + * from the specified file. Bytes from the file are converted into + * characters using the specified charset. + * + * @param source + * the path to the file to be scanned + * @param charset + * the charset used to convert bytes from the file + * into characters to be scanned + * @throws IOException + * if an I/O error occurs opening the source + * @since 10 + */ + public Scanner(Path source, Charset charset) throws IOException { + this(makeReadable(source, charset)); } /** @@ -735,6 +799,21 @@ WHITESPACE_PATTERN); } + /** + * Constructs a new {@code Scanner} that produces values scanned + * from the specified channel. Bytes from the source are converted into + * characters using the specified charset. + * + * @param source a channel to scan + * @param charset the encoding type used to convert bytes from the + * channel into characters to be scanned + * @since 10 + */ + public Scanner(ReadableByteChannel source, Charset charset) { + this(makeReadable(Objects.requireNonNull(source, "source"), charset), + WHITESPACE_PATTERN); + } + // Private primitives used to support scanning private void saveState() { @@ -1186,9 +1265,27 @@ modCount++; this.locale = locale; - DecimalFormat df = - (DecimalFormat)NumberFormat.getNumberInstance(locale); + + DecimalFormat df = null; + NumberFormat nf = NumberFormat.getNumberInstance(locale); DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale); + if (nf instanceof DecimalFormat) { + df = (DecimalFormat) nf; + } else { + + // In case where NumberFormat.getNumberInstance() returns + // other instance (non DecimalFormat) based on the provider + // used and java.text.spi.NumberFormatProvider implementations, + // DecimalFormat constructor is used to obtain the instance + LocaleProviderAdapter adapter = LocaleProviderAdapter + .getAdapter(NumberFormatProvider.class, locale); + if (!(adapter instanceof ResourceBundleBasedAdapter)) { + adapter = LocaleProviderAdapter.getResourceBundleBased(); + } + String[] all = adapter.getLocaleResources(locale) + .getNumberPatterns(); + df = new DecimalFormat(all[0], dfs); + } // These must be literalized to avoid collision with regex // metacharacters such as dot or parenthesis
--- a/src/java.base/share/classes/java/util/SimpleTimeZone.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/SimpleTimeZone.java Wed Dec 13 10:25:38 2017 -0800 @@ -548,12 +548,11 @@ computeOffset: if (useDaylight) { - synchronized (this) { - if (cacheStart != 0) { - if (date >= cacheStart && date < cacheEnd) { - offset += dstSavings; - break computeOffset; - } + Cache cache = this.cache; + if (cache != null) { + if (date >= cache.start && date < cache.end) { + offset += dstSavings; + break computeOffset; } } BaseCalendar cal = date >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER ? @@ -671,14 +670,13 @@ } private int getOffset(BaseCalendar cal, BaseCalendar.Date cdate, int year, long time) { - synchronized (this) { - if (cacheStart != 0) { - if (time >= cacheStart && time < cacheEnd) { - return rawOffset + dstSavings; - } - if (year == cacheYear) { - return rawOffset; - } + Cache cache = this.cache; + if (cache != null) { + if (time >= cache.start && time < cache.end) { + return rawOffset + dstSavings; + } + if (year == cache.year) { + return rawOffset; } } @@ -689,11 +687,7 @@ if (time >= start && time < end) { offset += dstSavings; } - synchronized (this) { - cacheYear = year; - cacheStart = start; - cacheEnd = end; - } + this.cache = new Cache(year, start, end); } else { if (time < end) { // TODO: support Gregorian cutover. The previous year @@ -711,12 +705,7 @@ } } if (start <= end) { - synchronized (this) { - // The start and end transitions are in multiple years. - cacheYear = (long) startYear - 1; - cacheStart = start; - cacheEnd = end; - } + this.cache = new Cache((long) startYear - 1, start, end); } } return offset; @@ -876,7 +865,7 @@ * Generates the hash code for the SimpleDateFormat object. * @return the hash code for this object */ - public synchronized int hashCode() + public int hashCode() { return startMonth ^ startDay ^ startDayOfWeek ^ startTime ^ endMonth ^ endDay ^ endDayOfWeek ^ endTime ^ rawOffset; @@ -1201,19 +1190,27 @@ /** * Cache values representing a single period of daylight saving - * time. When the cache values are valid, cacheStart is the start - * time (inclusive) of daylight saving time and cacheEnd is the - * end time (exclusive). + * time. Cache.start is the start time (inclusive) of daylight + * saving time and Cache.end is the end time (exclusive). * - * cacheYear has a year value if both cacheStart and cacheEnd are - * in the same year. cacheYear is set to startYear - 1 if - * cacheStart and cacheEnd are in different years. cacheStart is 0 - * if the cache values are void. cacheYear is a long to support - * Integer.MIN_VALUE - 1 (JCK requirement). + * Cache.year has a year value if both Cache.start and Cache.end are + * in the same year. Cache.year is set to startYear - 1 if + * Cache.start and Cache.end are in different years. + * Cache.year is a long to support Integer.MIN_VALUE - 1 (JCK requirement). */ - private transient long cacheYear; - private transient long cacheStart; - private transient long cacheEnd; + private static final class Cache { + final long year; + final long start; + final long end; + + Cache(long year, long start, long end) { + this.year = year; + this.start = start; + this.end = end; + } + } + + private transient volatile Cache cache; /** * Constants specifying values of startMode and endMode. @@ -1282,9 +1279,8 @@ // Maximum number of rules. private static final int MAX_RULE_NUM = 6; - private synchronized void invalidateCache() { - cacheYear = startYear - 1; - cacheStart = cacheEnd = 0; + private void invalidateCache() { + cache = null; } //----------------------------------------------------------------------
--- a/src/java.base/share/classes/java/util/spi/LocaleNameProvider.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/spi/LocaleNameProvider.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package java.util.spi; import java.util.Locale; +import java.util.Objects; /** * An abstract class for service providers that @@ -141,4 +142,54 @@ * @see java.util.Locale#getDisplayVariant(java.util.Locale) */ public abstract String getDisplayVariant(String variant, Locale locale); + + /** + * Returns a localized name for the given + * <a href="../Locale.html#def_locale_extension">Unicode extension</a> key, + * and the given locale that is appropriate for display to the user. + * If the name returned cannot be localized according to {@code locale}, + * this method returns null. + * @implSpec the default implementation returns {@code null}. + * @param key the Unicode Extension key, not null. + * @param locale the desired locale, not null. + * @return the name of the given key string for the specified locale, + * or null if it's not available. + * @exception NullPointerException if {@code key} or {@code locale} is null + * @exception IllegalArgumentException if {@code locale} isn't + * one of the locales returned from + * {@link java.util.spi.LocaleServiceProvider#getAvailableLocales() + * getAvailableLocales()}. + * @since 10 + */ + public String getDisplayUnicodeExtensionKey(String key, Locale locale) { + Objects.requireNonNull(key); + Objects.requireNonNull(locale); + return null; + } + + /** + * Returns a localized name for the given + * <a href="../Locale.html#def_locale_extension">Unicode extension</a> type, + * and the given locale that is appropriate for display to the user. + * If the name returned cannot be localized according to {@code locale}, + * this method returns null. + * @implSpec the default implementation returns {@code null}. + * @param type the Unicode Extension type, not null. + * @param key the Unicode Extension key for this {@code type}, not null. + * @param locale the desired locale, not null. + * @return the name of the given type string for the specified locale, + * or null if it's not available. + * @exception NullPointerException if {@code key}, {@code type} or {@code locale} is null + * @exception IllegalArgumentException if {@code locale} isn't + * one of the locales returned from + * {@link java.util.spi.LocaleServiceProvider#getAvailableLocales() + * getAvailableLocales()}. + * @since 10 + */ + public String getDisplayUnicodeExtensionType(String type, String key, Locale locale) { + Objects.requireNonNull(type); + Objects.requireNonNull(key); + Objects.requireNonNull(locale); + return null; + } }
--- a/src/java.base/share/classes/java/util/zip/Deflater.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/zip/Deflater.java Wed Dec 13 10:25:38 2017 -0800 @@ -67,12 +67,26 @@ * } * </pre></blockquote> * + * @apiNote + * To release resources used by this {@code Deflater}, the {@link #end()} method + * should be called explicitly. Subclasses are responsible for the cleanup of resources + * acquired by the subclass. Subclasses that override {@link #finalize()} in order + * to perform cleanup should be modified to use alternative cleanup mechanisms such + * as {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method. + * + * @implSpec + * If this {@code Deflater} has been subclassed and the {@code end} method has been + * overridden, the {@code end} method will be called by the finalization when the + * deflater is unreachable. But the subclasses should not depend on this specific + * implementation; the finalization is not reliable and the {@code finalize} method + * is deprecated to be removed. + * * @see Inflater * @author David Connelly * @since 1.1 */ -public -class Deflater { + +public class Deflater { private final ZStreamRef zsRef; private byte[] buf = new byte[0]; @@ -169,7 +183,9 @@ public Deflater(int level, boolean nowrap) { this.level = level; this.strategy = DEFAULT_STRATEGY; - this.zsRef = new ZStreamRef(init(level, DEFAULT_STRATEGY, nowrap)); + this.zsRef = ZStreamRef.get(this, + () -> init(level, DEFAULT_STRATEGY, nowrap), + Deflater::end); } /** @@ -534,38 +550,32 @@ /** * Closes the compressor and discards any unprocessed input. + * * This method should be called when the compressor is no longer - * being used, but will also be called automatically by the - * finalize() method. Once this method is called, the behavior - * of the Deflater object is undefined. + * being used. Once this method is called, the behavior of the + * Deflater object is undefined. */ public void end() { synchronized (zsRef) { - long addr = zsRef.address(); - zsRef.clear(); - if (addr != 0) { - end(addr); - buf = null; - } + zsRef.clean(); + buf = null; } } /** * Closes the compressor when garbage is collected. * - * @deprecated The {@code finalize} method has been deprecated. - * Subclasses that override {@code finalize} in order to perform cleanup - * should be modified to use alternative cleanup mechanisms and - * to remove the overriding {@code finalize} method. - * When overriding the {@code finalize} method, its implementation must explicitly - * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}. - * See the specification for {@link Object#finalize()} for further - * information about migration options. + * @deprecated The {@code finalize} method has been deprecated and will be + * removed. It is implemented as a no-op. Subclasses that override + * {@code finalize} in order to perform cleanup should be modified to use + * alternative cleanup mechanisms and to remove the overriding {@code finalize} + * method. The recommended cleanup for compressor is to explicitly call + * {@code end} method when it is no longer in use. If the {@code end} is + * not invoked explicitly the resource of the compressor will be released + * when the instance becomes unreachable. */ - @Deprecated(since="9") - protected void finalize() { - end(); - } + @Deprecated(since="9", forRemoval=true) + protected void finalize() {} private void ensureOpen() { assert Thread.holdsLock(zsRef);
--- a/src/java.base/share/classes/java/util/zip/Inflater.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/zip/Inflater.java Wed Dec 13 10:25:38 2017 -0800 @@ -66,13 +66,27 @@ * } * </pre></blockquote> * + * @apiNote + * To release resources used by this {@code Inflater}, the {@link #end()} method + * should be called explicitly. Subclasses are responsible for the cleanup of resources + * acquired by the subclass. Subclasses that override {@link #finalize()} in order + * to perform cleanup should be modified to use alternative cleanup mechanisms such + * as {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method. + * + * @implSpec + * If this {@code Inflater} has been subclassed and the {@code end} method has been + * overridden, the {@code end} method will be called by the finalization when the + * inflater is unreachable. But the subclasses should not depend on this specific + * implementation; the finalization is not reliable and the {@code finalize} method + * is deprecated to be removed. + * * @see Deflater * @author David Connelly * @since 1.1 * */ -public -class Inflater { + +public class Inflater { private final ZStreamRef zsRef; private byte[] buf = defaultBuf; @@ -101,7 +115,7 @@ * @param nowrap if true then support GZIP compatible compression */ public Inflater(boolean nowrap) { - zsRef = new ZStreamRef(init(nowrap)); + this.zsRef = ZStreamRef.get(this, () -> init(nowrap), Inflater::end); } /** @@ -361,38 +375,37 @@ /** * Closes the decompressor and discards any unprocessed input. + * * This method should be called when the decompressor is no longer - * being used, but will also be called automatically by the finalize() - * method. Once this method is called, the behavior of the Inflater - * object is undefined. + * being used. Once this method is called, the behavior of the + * Inflater object is undefined. */ public void end() { synchronized (zsRef) { - long addr = zsRef.address(); - zsRef.clear(); - if (addr != 0) { - end(addr); - buf = null; - } + zsRef.clean(); + buf = null; } } /** * Closes the decompressor when garbage is collected. * - * @deprecated The {@code finalize} method has been deprecated. - * Subclasses that override {@code finalize} in order to perform cleanup - * should be modified to use alternative cleanup mechanisms and - * to remove the overriding {@code finalize} method. - * When overriding the {@code finalize} method, its implementation must explicitly - * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}. - * See the specification for {@link Object#finalize()} for further - * information about migration options. + * @implSpec + * If this {@code Inflater} has been subclassed and the {@code end} method + * has been overridden, the {@code end} method will be called when the + * inflater is unreachable. + * + * @deprecated The {@code finalize} method has been deprecated and will be + * removed. It is implemented as a no-op. Subclasses that override + * {@code finalize} in order to perform cleanup should be modified to use + * alternative cleanup mechanisms and remove the overriding {@code finalize} + * method. The recommended cleanup for compressor is to explicitly call + * {@code end} method when it is no longer in use. If the {@code end} is + * not invoked explicitly the resource of the compressor will be released + * when the instance becomes unreachable, */ - @Deprecated(since="9") - protected void finalize() { - end(); - } + @Deprecated(since="9", forRemoval=true) + protected void finalize() {} private void ensureOpen () { assert Thread.holdsLock(zsRef);
--- a/src/java.base/share/classes/java/util/zip/ZStreamRef.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/zip/ZStreamRef.java Wed Dec 13 10:25:38 2017 -0800 @@ -25,22 +25,89 @@ package java.util.zip; +import java.util.function.LongConsumer; +import java.util.function.LongSupplier; +import java.lang.ref.Cleaner.Cleanable; +import jdk.internal.ref.CleanerFactory; + /** - * A reference to the native zlib's z_stream structure. + * A reference to the native zlib's z_stream structure. It also + * serves as the "cleaner" to clean up the native resource when + * the deflater or infalter is ended, closed or cleaned. */ +class ZStreamRef implements Runnable { -class ZStreamRef { + private LongConsumer end; + private long address; + private final Cleanable cleanable; - private volatile long address; - ZStreamRef (long address) { - this.address = address; + private ZStreamRef (Object owner, LongSupplier addr, LongConsumer end) { + this.cleanable = CleanerFactory.cleaner().register(owner, this); + this.end = end; + this.address = addr.getAsLong(); } long address() { return address; } - void clear() { + void clean() { + cleanable.clean(); + } + + public synchronized void run() { + long addr = address; address = 0; + if (addr != 0) { + end.accept(addr); + } + } + + private ZStreamRef (LongSupplier addr, LongConsumer end) { + this.cleanable = null; + this.end = end; + this.address = addr.getAsLong(); + } + + /* + * If {@code Inflater/Deflater} has been subclassed and the {@code end} method + * is overridden, uses {@code finalizer} mechanism for resource cleanup. So + * {@code end} method can be called when the {@code Inflater/Deflater} is + * unreachable. This mechanism will be removed when the {@code finalize} method + * is removed from {@code Inflater/Deflater}. + */ + static ZStreamRef get(Object owner, LongSupplier addr, LongConsumer end) { + Class<?> clz = owner.getClass(); + while (clz != Deflater.class && clz != Inflater.class) { + try { + clz.getDeclaredMethod("end"); + return new FinalizableZStreamRef(owner, addr, end); + } catch (NoSuchMethodException nsme) {} + clz = clz.getSuperclass(); + } + return new ZStreamRef(owner, addr, end); + } + + private static class FinalizableZStreamRef extends ZStreamRef { + final Object owner; + + FinalizableZStreamRef (Object owner, LongSupplier addr, LongConsumer end) { + super(addr, end); + this.owner = owner; + } + + @Override + void clean() { + run(); + } + + @Override + @SuppressWarnings("deprecation") + protected void finalize() { + if (owner instanceof Inflater) + ((Inflater)owner).end(); + else + ((Deflater)owner).end(); + } } }
--- a/src/java.base/share/classes/java/util/zip/ZipCoder.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/zip/ZipCoder.java Wed Dec 13 10:25:38 2017 -0800 @@ -28,72 +28,60 @@ import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; +import java.nio.charset.CharacterCodingException; import java.nio.charset.CodingErrorAction; -import java.util.Arrays; -import sun.nio.cs.ArrayDecoder; -import sun.nio.cs.ArrayEncoder; + +import static java.nio.charset.StandardCharsets.UTF_8; /** * Utility class for zipfile name and comment decoding and encoding */ -final class ZipCoder { +class ZipCoder { - private static boolean isASCII(byte[] ba, int off, int len) { - for (int i = off; i < off + len; i++) { - if (ba[i] < 0) - return false; + private static final jdk.internal.misc.JavaLangAccess JLA = + jdk.internal.misc.SharedSecrets.getJavaLangAccess(); + + static final class UTF8 extends ZipCoder { + + UTF8(Charset utf8) { + super(utf8); } - return true; + + @Override + boolean isUTF8() { + return true; + } + + @Override + String toString(byte[] ba, int off, int length) { + return JLA.newStringUTF8NoRepl(ba, off, length); + } + + @Override + byte[] getBytes(String s) { + return JLA.getBytesUTF8NoRepl(s); + } } - private static boolean hasReplaceChar(byte[] ba) { - for (int i = 0; i < ba.length; i++) { - if (ba[i] == (byte)'?') - return true; - } - return false; + // UTF_8.ArrayEn/Decoder is stateless, so make it singleton. + private static ZipCoder utf8 = new UTF8(UTF_8); + + public static ZipCoder get(Charset charset) { + if (charset == UTF_8) + return utf8; + return new ZipCoder(charset); } String toString(byte[] ba, int off, int length) { + try { + return decoder().decode(ByteBuffer.wrap(ba, off, length)).toString(); - // fastpath for UTF-8 cs and ascii only name, leverage the - // compact string impl to avoid the unnecessary char[] copy/ - // paste. A temporary workaround before we have better approach, - // such as a String constructor that throws exception for - // malformed and/or unmappable characters, instead of silently - // replacing with repl char - if (isUTF8 && isASCII(ba, off, length)) { - return new String(ba, off, length, cs); + } catch (CharacterCodingException x) { + throw new IllegalArgumentException(x); } - - CharsetDecoder cd = decoder().reset(); - int len = (int)(length * cd.maxCharsPerByte()); - char[] ca = new char[len]; - if (len == 0) - return new String(ca); - // UTF-8 only for now. Other ArrayDeocder only handles - // CodingErrorAction.REPLACE mode. ZipCoder uses - // REPORT mode. - if (isUTF8 && cd instanceof ArrayDecoder) { - int clen = ((ArrayDecoder)cd).decode(ba, off, length, ca); - if (clen == -1) // malformed - throw new IllegalArgumentException("MALFORMED"); - return new String(ca, 0, clen); - } - ByteBuffer bb = ByteBuffer.wrap(ba, off, length); - CharBuffer cb = CharBuffer.wrap(ca); - CoderResult cr = cd.decode(bb, cb, true); - if (!cr.isUnderflow()) - throw new IllegalArgumentException(cr.toString()); - cr = cd.flush(cb); - if (!cr.isUnderflow()) - throw new IllegalArgumentException(cr.toString()); - return new String(ca, 0, cb.position()); } String toString(byte[] ba, int length) { @@ -105,84 +93,47 @@ } byte[] getBytes(String s) { - if (isUTF8) { - // fastpath for UTF8. should only occur when the string - // has malformed surrogates. A postscan should still be - // faster and use less memory. - byte[] ba = s.getBytes(cs); - if (!hasReplaceChar(ba)) { - return ba; + try { + ByteBuffer bb = encoder().encode(CharBuffer.wrap(s)); + int pos = bb.position(); + int limit = bb.limit(); + if (bb.hasArray() && pos == 0 && limit == bb.capacity()) { + return bb.array(); } + byte[] bytes = new byte[bb.limit() - bb.position()]; + bb.get(bytes); + return bytes; + } catch (CharacterCodingException x) { + throw new IllegalArgumentException(x); } - CharsetEncoder ce = encoder().reset(); - char[] ca = s.toCharArray(); - int len = (int)(ca.length * ce.maxBytesPerChar()); - byte[] ba = new byte[len]; - if (len == 0) - return ba; - // UTF-8 only for now. Other ArrayDeocder only handles - // CodingErrorAction.REPLACE mode. - if (isUTF8 && ce instanceof ArrayEncoder) { - int blen = ((ArrayEncoder)ce).encode(ca, 0, ca.length, ba); - if (blen == -1) // malformed - throw new IllegalArgumentException("MALFORMED"); - return Arrays.copyOf(ba, blen); - } - ByteBuffer bb = ByteBuffer.wrap(ba); - CharBuffer cb = CharBuffer.wrap(ca); - CoderResult cr = ce.encode(cb, bb, true); - if (!cr.isUnderflow()) - throw new IllegalArgumentException(cr.toString()); - cr = ce.flush(bb); - if (!cr.isUnderflow()) - throw new IllegalArgumentException(cr.toString()); - if (bb.position() == ba.length) // defensive copy? - return ba; - else - return Arrays.copyOf(ba, bb.position()); } // assume invoked only if "this" is not utf8 byte[] getBytesUTF8(String s) { - if (isUTF8) - return getBytes(s); - if (utf8 == null) - utf8 = new ZipCoder(StandardCharsets.UTF_8); return utf8.getBytes(s); } String toStringUTF8(byte[] ba, int len) { - return toStringUTF8(ba, 0, len); + return utf8.toString(ba, 0, len); } String toStringUTF8(byte[] ba, int off, int len) { - if (isUTF8) - return toString(ba, off, len); - if (utf8 == null) - utf8 = new ZipCoder(StandardCharsets.UTF_8); return utf8.toString(ba, off, len); } boolean isUTF8() { - return isUTF8; + return false; } private Charset cs; private CharsetDecoder dec; private CharsetEncoder enc; - private boolean isUTF8; - private ZipCoder utf8; private ZipCoder(Charset cs) { this.cs = cs; - this.isUTF8 = cs.name().equals(StandardCharsets.UTF_8.name()); } - static ZipCoder get(Charset charset) { - return new ZipCoder(charset); - } - - private CharsetDecoder decoder() { + protected CharsetDecoder decoder() { if (dec == null) { dec = cs.newDecoder() .onMalformedInput(CodingErrorAction.REPORT) @@ -191,7 +142,7 @@ return dec; } - private CharsetEncoder encoder() { + protected CharsetEncoder encoder() { if (enc == null) { enc = cs.newEncoder() .onMalformedInput(CodingErrorAction.REPORT)
--- a/src/java.base/share/classes/java/util/zip/ZipFile.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java Wed Dec 13 10:25:38 2017 -0800 @@ -31,22 +31,24 @@ import java.io.EOFException; import java.io.File; import java.io.RandomAccessFile; +import java.io.UncheckedIOException; +import java.lang.ref.Cleaner.Cleanable; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.Path; import java.nio.file.Files; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Deque; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; -import java.util.Map; import java.util.Objects; import java.util.NoSuchElementException; +import java.util.Set; import java.util.Spliterator; import java.util.Spliterators; import java.util.WeakHashMap; @@ -61,8 +63,8 @@ import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.VM; import jdk.internal.perf.PerfCounter; +import jdk.internal.ref.CleanerFactory; -import static java.util.zip.ZipConstants.*; import static java.util.zip.ZipConstants64.*; import static java.util.zip.ZipUtils.*; @@ -73,6 +75,21 @@ * or method in this class will cause a {@link NullPointerException} to be * thrown. * + * @apiNote + * To release resources used by this {@code ZipFile}, the {@link #close()} method + * should be called explicitly or by try-with-resources. Subclasses are responsible + * for the cleanup of resources acquired by the subclass. Subclasses that override + * {@link #finalize()} in order to perform cleanup should be modified to use alternative + * cleanup mechanisms such as {@link java.lang.ref.Cleaner} and remove the overriding + * {@code finalize} method. + * + * @implSpec + * If this {@code ZipFile} has been subclassed and the {@code close} method has + * been overridden, the {@code close} method will be called by the finalization + * when {@code ZipFile} is unreachable. But the subclasses should not depend on + * this specific implementation; the finalization is not reliable and the + * {@code finalize} method is deprecated to be removed. + * * @author David Connelly * @since 1.1 */ @@ -81,9 +98,15 @@ private final String name; // zip file name private volatile boolean closeRequested; - private Source zsrc; private ZipCoder zc; + // The "resource" used by this zip file that needs to be + // cleaned after use. + // a) the input streams that need to be closed + // b) the list of cached Inflater objects + // c) the "native" source of this zip file. + private final CleanableResource res; + private static final int STORED = ZipEntry.STORED; private static final int DEFLATED = ZipEntry.DEFLATED; @@ -214,10 +237,13 @@ } } Objects.requireNonNull(charset, "charset"); + this.zc = ZipCoder.get(charset); this.name = name; long t0 = System.nanoTime(); - this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0); + + this.res = CleanableResource.get(this, file, mode); + PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0); PerfCounter.getZipFileCount().increment(); } @@ -284,10 +310,10 @@ public String getComment() { synchronized (this) { ensureOpen(); - if (zsrc.comment == null) { + if (res.zsrc.comment == null) { return null; } - return zc.toString(zsrc.comment); + return zc.toString(res.zsrc.comment); } } @@ -318,7 +344,7 @@ synchronized (this) { ensureOpen(); byte[] bname = zc.getBytes(name); - int pos = zsrc.getEntryPos(bname, true); + int pos = res.zsrc.getEntryPos(bname, true); if (pos != -1) { return getZipEntry(name, bname, pos, func); } @@ -326,10 +352,6 @@ return null; } - // The outstanding inputstreams that need to be closed, - // mapped to the inflater objects they use. - private final Map<InputStream, Inflater> streams = new WeakHashMap<>(); - /** * Returns an input stream for reading the contents of the specified * zip file entry. @@ -348,6 +370,8 @@ Objects.requireNonNull(entry, "entry"); int pos = -1; ZipFileInputStream in = null; + Source zsrc = res.zsrc; + Set<InputStream> istreams = res.istreams; synchronized (this) { ensureOpen(); if (Objects.equals(lastEntryName, entry.name)) { @@ -363,8 +387,8 @@ in = new ZipFileInputStream(zsrc.cen, pos); switch (CENHOW(zsrc.cen, pos)) { case STORED: - synchronized (streams) { - streams.put(in, null); + synchronized (istreams) { + istreams.add(in); } return in; case DEFLATED: @@ -377,10 +401,9 @@ if (size <= 0) { size = 4096; } - Inflater inf = getInflater(); - InputStream is = new ZipFileInflaterInputStream(in, inf, (int)size); - synchronized (streams) { - streams.put(is, inf); + InputStream is = new ZipFileInflaterInputStream(in, res, (int)size); + synchronized (istreams) { + istreams.add(is); } return is; default: @@ -392,25 +415,30 @@ private class ZipFileInflaterInputStream extends InflaterInputStream { private volatile boolean closeRequested; private boolean eof = false; + private final Cleanable cleanable; - ZipFileInflaterInputStream(ZipFileInputStream zfin, Inflater inf, - int size) { + ZipFileInflaterInputStream(ZipFileInputStream zfin, + CleanableResource res, int size) { + this(zfin, res, res.getInflater(), size); + } + + private ZipFileInflaterInputStream(ZipFileInputStream zfin, + CleanableResource res, + Inflater inf, int size) { super(zfin, inf, size); - } + this.cleanable = CleanerFactory.cleaner().register(this, + () -> res.releaseInflater(inf)); + } public void close() throws IOException { if (closeRequested) return; closeRequested = true; - super.close(); - Inflater inf; - synchronized (streams) { - inf = streams.remove(this); + synchronized (res.istreams) { + res.istreams.remove(this); } - if (inf != null) { - releaseInflater(inf); - } + cleanable.clean(); } // Override fill() method to provide an extra "dummy" byte @@ -436,44 +464,8 @@ return (avail > (long) Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) avail); } - - @SuppressWarnings("deprecation") - protected void finalize() throws Throwable { - close(); - } } - /* - * Gets an inflater from the list of available inflaters or allocates - * a new one. - */ - private Inflater getInflater() { - Inflater inf; - synchronized (inflaterCache) { - while ((inf = inflaterCache.poll()) != null) { - if (!inf.ended()) { - return inf; - } - } - } - return new Inflater(true); - } - - /* - * Releases the specified inflater to the list of available inflaters. - */ - private void releaseInflater(Inflater inf) { - if (!inf.ended()) { - inf.reset(); - synchronized (inflaterCache) { - inflaterCache.add(inf); - } - } - } - - // List of available Inflater objects for decompression - private final Deque<Inflater> inflaterCache = new ArrayDeque<>(); - /** * Returns the path name of the ZIP file. * @return the path name of the ZIP file @@ -518,7 +510,7 @@ throw new NoSuchElementException(); } // each "entry" has 3 ints in table entries - return (T)getZipEntry(null, null, zsrc.getEntryPos(i++ * 3), gen); + return (T)getZipEntry(null, null, res.zsrc.getEntryPos(i++ * 3), gen); } } @@ -536,14 +528,14 @@ public Enumeration<? extends ZipEntry> entries() { synchronized (this) { ensureOpen(); - return new ZipEntryIterator<ZipEntry>(zsrc.total, ZipEntry::new); + return new ZipEntryIterator<ZipEntry>(res.zsrc.total, ZipEntry::new); } } private Enumeration<JarEntry> entries(Function<String, JarEntry> func) { synchronized (this) { ensureOpen(); - return new ZipEntryIterator<JarEntry>(zsrc.total, func); + return new ZipEntryIterator<JarEntry>(res.zsrc.total, func); } } @@ -568,7 +560,7 @@ if (index >= 0 && index < fence) { synchronized (ZipFile.this) { ensureOpen(); - action.accept(gen.apply(zsrc.getEntryPos(index++ * 3))); + action.accept(gen.apply(res.zsrc.getEntryPos(index++ * 3))); } return true; } @@ -589,13 +581,13 @@ public Stream<? extends ZipEntry> stream() { synchronized (this) { ensureOpen(); - return StreamSupport.stream(new EntrySpliterator<>(0, zsrc.total, + return StreamSupport.stream(new EntrySpliterator<>(0, res.zsrc.total, pos -> getZipEntry(null, null, pos, ZipEntry::new)), false); } } private String getEntryName(int pos) { - byte[] cen = zsrc.cen; + byte[] cen = res.zsrc.cen; int nlen = CENNAM(cen, pos); int clen = CENCOM(cen, pos); int flag = CENFLG(cen, pos); @@ -620,7 +612,7 @@ synchronized (this) { ensureOpen(); return StreamSupport.stream( - new EntrySpliterator<>(0, zsrc.total, this::getEntryName), false); + new EntrySpliterator<>(0, res.zsrc.total, this::getEntryName), false); } } @@ -638,7 +630,7 @@ private Stream<JarEntry> stream(Function<String, JarEntry> func) { synchronized (this) { ensureOpen(); - return StreamSupport.stream(new EntrySpliterator<>(0, zsrc.total, + return StreamSupport.stream(new EntrySpliterator<>(0, res.zsrc.total, pos -> (JarEntry)getZipEntry(null, null, pos, func)), false); } } @@ -649,7 +641,7 @@ /* Checks ensureOpen() before invoke this method */ private ZipEntry getZipEntry(String name, byte[] bname, int pos, Function<String, ? extends ZipEntry> func) { - byte[] cen = zsrc.cen; + byte[] cen = res.zsrc.cen; int nlen = CENNAM(cen, pos); int elen = CENEXT(cen, pos); int clen = CENCOM(cen, pos); @@ -698,12 +690,170 @@ public int size() { synchronized (this) { ensureOpen(); - return zsrc.total; + return res.zsrc.total; + } + } + + private static class CleanableResource implements Runnable { + // The outstanding inputstreams that need to be closed + final Set<InputStream> istreams; + + // List of cached Inflater objects for decompression + Deque<Inflater> inflaterCache; + + final Cleanable cleanable; + + Source zsrc; + + CleanableResource(ZipFile zf, File file, int mode) throws IOException { + this.cleanable = CleanerFactory.cleaner().register(zf, this); + this.istreams = Collections.newSetFromMap(new WeakHashMap<>()); + this.inflaterCache = new ArrayDeque<>(); + this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0); + } + + void clean() { + cleanable.clean(); + } + + /* + * Gets an inflater from the list of available inflaters or allocates + * a new one. + */ + Inflater getInflater() { + Inflater inf; + synchronized (inflaterCache) { + if ((inf = inflaterCache.poll()) != null) { + return inf; + } + } + return new Inflater(true); + } + + /* + * Releases the specified inflater to the list of available inflaters. + */ + void releaseInflater(Inflater inf) { + Deque<Inflater> inflaters = this.inflaterCache; + if (inflaters != null) { + synchronized (inflaters) { + // double checked! + if (inflaters == this.inflaterCache) { + inf.reset(); + inflaters.add(inf); + return; + } + } + } + // inflaters cache already closed - just end it. + inf.end(); + } + + public void run() { + IOException ioe = null; + + // Release cached inflaters and close the cache first + Deque<Inflater> inflaters = this.inflaterCache; + if (inflaters != null) { + synchronized (inflaters) { + // no need to double-check as only one thread gets a + // chance to execute run() (Cleaner guarantee)... + Inflater inf; + while ((inf = inflaters.poll()) != null) { + inf.end(); + } + // close inflaters cache + this.inflaterCache = null; + } + } + + // Close streams, release their inflaters + if (istreams != null) { + synchronized (istreams) { + if (!istreams.isEmpty()) { + InputStream[] copy = istreams.toArray(new InputStream[0]); + istreams.clear(); + for (InputStream is : copy) { + try { + is.close(); + } catch (IOException e) { + if (ioe == null) ioe = e; + else ioe.addSuppressed(e); + } + } + } + } + } + + // Release zip src + if (zsrc != null) { + synchronized (zsrc) { + try { + Source.release(zsrc); + zsrc = null; + } catch (IOException e) { + if (ioe == null) ioe = e; + else ioe.addSuppressed(e); + } + } + } + if (ioe != null) { + throw new UncheckedIOException(ioe); + } + } + + CleanableResource(File file, int mode) + throws IOException { + this.cleanable = null; + this.istreams = Collections.newSetFromMap(new WeakHashMap<>()); + this.inflaterCache = new ArrayDeque<>(); + this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0); + } + + /* + * If {@code ZipFile} has been subclassed and the {@code close} method is + * overridden, uses the {@code finalizer} mechanism for resource cleanup. + * So {@code close} method can be called when the the {@code ZipFile} is + * unreachable. This mechanism will be removed when {@code finalize} method + * is removed from {@code ZipFile}. + */ + static CleanableResource get(ZipFile zf, File file, int mode) + throws IOException { + Class<?> clz = zf.getClass(); + while (clz != ZipFile.class) { + try { + clz.getDeclaredMethod("close"); + return new FinalizableResource(zf, file, mode); + } catch (NoSuchMethodException nsme) {} + clz = clz.getSuperclass(); + } + return new CleanableResource(zf, file, mode); + } + + static class FinalizableResource extends CleanableResource { + ZipFile zf; + FinalizableResource(ZipFile zf, File file, int mode) + throws IOException { + super(file, mode); + this.zf = zf; + } + + @Override + void clean() { + run(); + } + + @Override + @SuppressWarnings("deprecation") + protected void finalize() throws IOException { + zf.close(); + } } } /** * Closes the ZIP file. + * * <p> Closing this ZIP file will close all of the input streams * previously returned by invocations of the {@link #getInputStream * getInputStream} method. @@ -717,31 +867,12 @@ closeRequested = true; synchronized (this) { - // Close streams, release their inflaters - synchronized (streams) { - if (!streams.isEmpty()) { - Map<InputStream, Inflater> copy = new HashMap<>(streams); - streams.clear(); - for (Map.Entry<InputStream, Inflater> e : copy.entrySet()) { - e.getKey().close(); - Inflater inf = e.getValue(); - if (inf != null) { - inf.end(); - } - } - } - } - // Release cached inflaters - synchronized (inflaterCache) { - Inflater inf; - while ((inf = inflaterCache.poll()) != null) { - inf.end(); - } - } - // Release zip src - if (zsrc != null) { - Source.close(zsrc); - zsrc = null; + // Close streams, release their inflaters, release cached inflaters + // and release zip source + try { + res.clean(); + } catch (UncheckedIOException ioe) { + throw ioe.getCause(); } } } @@ -750,34 +881,26 @@ * Ensures that the system resources held by this ZipFile object are * released when there are no more references to it. * - * <p> - * Since the time when GC would invoke this method is undetermined, - * it is strongly recommended that applications invoke the {@code close} - * method as soon they have finished accessing this {@code ZipFile}. - * This will prevent holding up system resources for an undetermined - * length of time. + * @deprecated The {@code finalize} method has been deprecated and will be + * removed. It is implemented as a no-op. Subclasses that override + * {@code finalize} in order to perform cleanup should be modified to + * use alternative cleanup mechanisms and to remove the overriding + * {@code finalize} method. The recommended cleanup for ZipFile object + * is to explicitly invoke {@code close} method when it is no longer in + * use, or use try-with-resources. If the {@code close} is not invoked + * explicitly the resources held by this object will be released when + * the instance becomes unreachable. * - * @deprecated The {@code finalize} method has been deprecated. - * Subclasses that override {@code finalize} in order to perform cleanup - * should be modified to use alternative cleanup mechanisms and - * to remove the overriding {@code finalize} method. - * When overriding the {@code finalize} method, its implementation must explicitly - * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}. - * See the specification for {@link Object#finalize()} for further - * information about migration options. * @throws IOException if an I/O error has occurred - * @see java.util.zip.ZipFile#close() */ - @Deprecated(since="9") - protected void finalize() throws IOException { - close(); - } + @Deprecated(since="9", forRemoval=true) + protected void finalize() throws IOException {} private void ensureOpen() { if (closeRequested) { throw new IllegalStateException("zip file closed"); } - if (zsrc == null) { + if (res.zsrc == null) { throw new IllegalStateException("The object is not initialized."); } } @@ -798,7 +921,7 @@ protected long rem; // number of remaining bytes within entry protected long size; // uncompressed size of this entry - ZipFileInputStream(byte[] cen, int cenpos) throws IOException { + ZipFileInputStream(byte[] cen, int cenpos) { rem = CENSIZ(cen, cenpos); size = CENLEN(cen, cenpos); pos = CENOFF(cen, cenpos); @@ -808,10 +931,10 @@ checkZIP64(cen, cenpos); } // negative for lazy initialization, see getDataOffset(); - pos = - (pos + ZipFile.this.zsrc.locpos); + pos = - (pos + ZipFile.this.res.zsrc.locpos); } - private void checkZIP64(byte[] cen, int cenpos) throws IOException { + private void checkZIP64(byte[] cen, int cenpos) { int off = cenpos + CENHDR + CENNAM(cen, cenpos); int end = off + CENEXT(cen, cenpos); while (off + 4 < end) { @@ -857,7 +980,7 @@ if (pos <= 0) { byte[] loc = new byte[LOCHDR]; pos = -pos; - int len = ZipFile.this.zsrc.readFullyAt(loc, 0, loc.length, pos); + int len = ZipFile.this.res.zsrc.readFullyAt(loc, 0, loc.length, pos); if (len != LOCHDR) { throw new ZipException("ZipFile error reading zip file"); } @@ -882,7 +1005,7 @@ if (len <= 0) { return 0; } - len = ZipFile.this.zsrc.readAt(b, off, len, pos); + len = ZipFile.this.res.zsrc.readAt(b, off, len, pos); if (len > 0) { pos += len; rem -= len; @@ -932,15 +1055,11 @@ } closeRequested = true; rem = 0; - synchronized (streams) { - streams.remove(this); + synchronized (res.istreams) { + res.istreams.remove(this); } } - @SuppressWarnings("deprecation") - protected void finalize() { - close(); - } } /** @@ -952,6 +1071,7 @@ private String[] getMetaInfEntryNames() { synchronized (this) { ensureOpen(); + Source zsrc = res.zsrc; if (zsrc.metanames == null) { return null; } @@ -972,7 +1092,7 @@ new JavaUtilZipFileAccess() { @Override public boolean startsWithLocHeader(ZipFile zip) { - return zip.zsrc.startsWithLoc; + return zip.res.zsrc.startsWithLoc; } @Override public String[] getMetaInfEntryNames(ZipFile zip) { @@ -1080,7 +1200,7 @@ private static final HashMap<Key, Source> files = new HashMap<>(); - public static Source get(File file, boolean toDelete) throws IOException { + static Source get(File file, boolean toDelete) throws IOException { Key key = new Key(file, Files.readAttributes(file.toPath(), BasicFileAttributes.class)); Source src = null; @@ -1105,9 +1225,9 @@ } } - private static void close(Source src) throws IOException { + static void release(Source src) throws IOException { synchronized (files) { - if (--src.refs == 0) { + if (src != null && --src.refs == 0) { files.remove(src.key); src.close(); }
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java Wed Dec 13 10:25:38 2017 -0800 @@ -254,4 +254,23 @@ * given class loader. */ Stream<ModuleLayer> layers(ClassLoader loader); + + /** + * Returns a new string by decoding from the given utf8 bytes array. + * + * @param off the index of the first byte to decode + * @param len the number of bytes to decode + * @return the newly created string + * @throws IllegalArgumentException for malformed or unmappable bytes. + */ + String newStringUTF8NoRepl(byte[] bytes, int off, int len); + + /** + * Encode the given string into a sequence of bytes using utf8. + * + * @param s the string to encode + * @return the encoded bytes in utf8 + * @throws IllegalArgumentException for malformed surrogates + */ + byte[] getBytesUTF8NoRepl(String s); }
--- a/src/java.base/share/classes/jdk/internal/util/xml/PropertiesDefaultHandler.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/jdk/internal/util/xml/PropertiesDefaultHandler.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package jdk.internal.util.xml; import java.io.*; +import java.nio.charset.Charset; import java.util.InvalidPropertiesFormatException; import java.util.Map.Entry; import java.util.Properties; @@ -94,11 +95,11 @@ */ } - public void store(Properties props, OutputStream os, String comment, String encoding) + public void store(Properties props, OutputStream os, String comment, Charset charset) throws IOException { try { - XMLStreamWriter writer = new XMLStreamWriterImpl(os, encoding); + XMLStreamWriter writer = new XMLStreamWriterImpl(os, charset); writer.writeStartDocument(); writer.writeDTD(PROPS_DTD_DECL); writer.writeStartElement(ELEMENT_ROOT);
--- a/src/java.base/share/classes/jdk/internal/util/xml/XMLStreamWriter.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/jdk/internal/util/xml/XMLStreamWriter.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,9 @@ package jdk.internal.util.xml; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + /** * Basic XMLStreamWriter for writing simple XML files such as those * defined in java.util.Properties @@ -38,6 +41,7 @@ //Defaults the XML version to 1.0, and the encoding to utf-8 public static final String DEFAULT_XML_VERSION = "1.0"; public static final String DEFAULT_ENCODING = "UTF-8"; + public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; /** * Writes a start tag to the output. All writeStartElement methods
--- a/src/java.base/share/classes/jdk/internal/util/xml/impl/XMLStreamWriterImpl.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/jdk/internal/util/xml/impl/XMLStreamWriterImpl.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,7 +66,7 @@ private int _state = 0; private Element _currentEle; private XMLWriter _writer; - private String _encoding; + private Charset _charset; /** * This flag can be used to turn escaping off for content. It does * not apply to attribute content. @@ -79,26 +79,23 @@ System.getProperty("line.separator").toCharArray(); public XMLStreamWriterImpl(OutputStream os) throws XMLStreamException { - this(os, XMLStreamWriter.DEFAULT_ENCODING); + this(os, XMLStreamWriter.DEFAULT_CHARSET); } - public XMLStreamWriterImpl(OutputStream os, String encoding) + public XMLStreamWriterImpl(OutputStream os, Charset cs) throws XMLStreamException { - Charset cs = null; - if (encoding == null) { - _encoding = XMLStreamWriter.DEFAULT_ENCODING; + if (cs == null) { + _charset = XMLStreamWriter.DEFAULT_CHARSET; } else { try { - cs = getCharset(encoding); + _charset = checkCharset(cs); } catch (UnsupportedEncodingException e) { throw new XMLStreamException(e); } - - this._encoding = encoding; } - _writer = new XMLWriter(os, encoding, cs); + _writer = new XMLWriter(os, null, _charset); } /** @@ -108,7 +105,7 @@ * @throws XMLStreamException */ public void writeStartDocument() throws XMLStreamException { - writeStartDocument(_encoding, XMLStreamWriter.DEFAULT_XML_VERSION); + writeStartDocument(_charset.name(), XMLStreamWriter.DEFAULT_XML_VERSION); } /** @@ -118,7 +115,7 @@ * @throws XMLStreamException */ public void writeStartDocument(String version) throws XMLStreamException { - writeStartDocument(_encoding, version, null); + writeStartDocument(_charset.name(), version, null); } /** @@ -155,7 +152,7 @@ _state = STATE_XML_DECL; String enc = encoding; if (enc == null) { - enc = _encoding; + enc = _charset.name(); } else { //check if the encoding is supported try { @@ -564,6 +561,20 @@ return cs; } + /** + * Checks for charset support. + * @param charset the specified charset + * @return the charset + * @throws UnsupportedEncodingException if the charset is not supported + */ + private Charset checkCharset(Charset charset) throws UnsupportedEncodingException { + if (charset.name().equalsIgnoreCase("UTF-32")) { + throw new UnsupportedEncodingException("The basic XMLWriter does " + + "not support " + charset.name()); + } + return charset; + } + /* * Start of Internal classes. *
--- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.java Wed Dec 13 10:25:38 2017 -0800 @@ -268,7 +268,7 @@ Locale locale = Locale.getDefault(); ostream.println(LOCALE_SETTINGS); ostream.println(INDENT + "default locale = " + - locale.getDisplayLanguage()); + locale.getDisplayName()); ostream.println(INDENT + "default display locale = " + Locale.getDefault(Category.DISPLAY).getDisplayName()); ostream.println(INDENT + "default format locale = " +
--- a/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java Wed Dec 13 10:25:38 2017 -0800 @@ -63,8 +63,8 @@ return new Encoder(this); } - private static class Decoder extends CharsetDecoder - implements ArrayDecoder { + private static class Decoder extends CharsetDecoder { + private Decoder(Charset cs) { super(cs, 1.0f, 1.0f); } @@ -124,23 +124,10 @@ else return decodeBufferLoop(src, dst); } - - public int decode(byte[] src, int sp, int len, char[] dst) { - if (len > dst.length) - len = dst.length; - int dp = 0; - while (dp < len) - dst[dp++] = (char)(src[sp++] & 0xff); - return dp; - } - - public boolean isASCIICompatible() { - return true; - } } - private static class Encoder extends CharsetEncoder - implements ArrayEncoder { + private static class Encoder extends CharsetEncoder { + private Encoder(Charset cs) { super(cs, 1.0f, 1.0f); } @@ -271,39 +258,5 @@ else return encodeBufferLoop(src, dst); } - - private byte repl = (byte)'?'; - protected void implReplaceWith(byte[] newReplacement) { - repl = newReplacement[0]; - } - - public int encode(char[] src, int sp, int len, byte[] dst) { - int dp = 0; - int slen = Math.min(len, dst.length); - int sl = sp + slen; - while (sp < sl) { - int ret = encodeISOArray(src, sp, dst, dp, slen); - sp = sp + ret; - dp = dp + ret; - if (ret != slen) { - char c = src[sp++]; - if (Character.isHighSurrogate(c) && sp < sl && - Character.isLowSurrogate(src[sp])) { - if (len > dst.length) { - sl++; - len--; - } - sp++; - } - dst[dp++] = repl; - slen = Math.min((sl - sp), (dst.length - dp)); - } - } - return dp; - } - - public boolean isASCIICompatible() { - return true; - } } }
--- a/src/java.base/share/classes/sun/nio/cs/US_ASCII.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/nio/cs/US_ASCII.java Wed Dec 13 10:25:38 2017 -0800 @@ -58,8 +58,7 @@ return new Encoder(this); } - private static class Decoder extends CharsetDecoder - implements ArrayDecoder { + private static class Decoder extends CharsetDecoder { private Decoder(Charset cs) { super(cs, 1.0f, 1.0f); @@ -128,32 +127,9 @@ else return decodeBufferLoop(src, dst); } - - private char repl = '\uFFFD'; - protected void implReplaceWith(String newReplacement) { - repl = newReplacement.charAt(0); - } - - public int decode(byte[] src, int sp, int len, char[] dst) { - int dp = 0; - len = Math.min(len, dst.length); - while (dp < len) { - byte b = src[sp++]; - if (b >= 0) - dst[dp++] = (char)b; - else - dst[dp++] = repl; - } - return dp; - } - - public boolean isASCIICompatible() { - return true; - } } - private static class Encoder extends CharsetEncoder - implements ArrayEncoder { + private static class Encoder extends CharsetEncoder { private Encoder(Charset cs) { super(cs, 1.0f, 1.0f); @@ -237,36 +213,5 @@ return encodeBufferLoop(src, dst); } - private byte repl = (byte)'?'; - protected void implReplaceWith(byte[] newReplacement) { - repl = newReplacement[0]; - } - - public int encode(char[] src, int sp, int len, byte[] dst) { - int dp = 0; - int sl = sp + Math.min(len, dst.length); - while (sp < sl) { - char c = src[sp++]; - if (c < 0x80) { - dst[dp++] = (byte)c; - continue; - } - if (Character.isHighSurrogate(c) && sp < sl && - Character.isLowSurrogate(src[sp])) { - if (len > dst.length) { - sl++; - len--; - } - sp++; - } - dst[dp++] = repl; - } - return dp; - } - - public boolean isASCIICompatible() { - return true; - } } - }
--- a/src/java.base/share/classes/sun/nio/cs/UTF_8.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/nio/cs/UTF_8.java Wed Dec 13 10:25:38 2017 -0800 @@ -80,8 +80,8 @@ dst.position(dp - dst.arrayOffset()); } - private static class Decoder extends CharsetDecoder - implements ArrayDecoder { + private static class Decoder extends CharsetDecoder { + private Decoder(Charset cs) { super(cs, 1.0f, 1.0f); } @@ -423,142 +423,9 @@ bb.position(sp); return bb; } - - // returns -1 if there is/are malformed byte(s) and the - // "action" for malformed input is not REPLACE. - public int decode(byte[] sa, int sp, int len, char[] da) { - final int sl = sp + len; - int dp = 0; - int dlASCII = Math.min(len, da.length); - ByteBuffer bb = null; // only necessary if malformed - - // ASCII only optimized loop - while (dp < dlASCII && sa[sp] >= 0) - da[dp++] = (char) sa[sp++]; - - while (sp < sl) { - int b1 = sa[sp++]; - if (b1 >= 0) { - // 1 byte, 7 bits: 0xxxxxxx - da[dp++] = (char) b1; - } else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) { - // 2 bytes, 11 bits: 110xxxxx 10xxxxxx - if (sp < sl) { - int b2 = sa[sp++]; - if (isNotContinuation(b2)) { - if (malformedInputAction() != CodingErrorAction.REPLACE) - return -1; - da[dp++] = replacement().charAt(0); - sp--; // malformedN(bb, 2) always returns 1 - } else { - da[dp++] = (char) (((b1 << 6) ^ b2)^ - (((byte) 0xC0 << 6) ^ - ((byte) 0x80 << 0))); - } - continue; - } - if (malformedInputAction() != CodingErrorAction.REPLACE) - return -1; - da[dp++] = replacement().charAt(0); - return dp; - } else if ((b1 >> 4) == -2) { - // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx - if (sp + 1 < sl) { - int b2 = sa[sp++]; - int b3 = sa[sp++]; - if (isMalformed3(b1, b2, b3)) { - if (malformedInputAction() != CodingErrorAction.REPLACE) - return -1; - da[dp++] = replacement().charAt(0); - sp -= 3; - bb = getByteBuffer(bb, sa, sp); - sp += malformedN(bb, 3).length(); - } else { - char c = (char)((b1 << 12) ^ - (b2 << 6) ^ - (b3 ^ - (((byte) 0xE0 << 12) ^ - ((byte) 0x80 << 6) ^ - ((byte) 0x80 << 0)))); - if (Character.isSurrogate(c)) { - if (malformedInputAction() != CodingErrorAction.REPLACE) - return -1; - da[dp++] = replacement().charAt(0); - } else { - da[dp++] = c; - } - } - continue; - } - if (malformedInputAction() != CodingErrorAction.REPLACE) - return -1; - if (sp < sl && isMalformed3_2(b1, sa[sp])) { - da[dp++] = replacement().charAt(0); - continue; - - } - da[dp++] = replacement().charAt(0); - return dp; - } else if ((b1 >> 3) == -2) { - // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - if (sp + 2 < sl) { - int b2 = sa[sp++]; - int b3 = sa[sp++]; - int b4 = sa[sp++]; - int uc = ((b1 << 18) ^ - (b2 << 12) ^ - (b3 << 6) ^ - (b4 ^ - (((byte) 0xF0 << 18) ^ - ((byte) 0x80 << 12) ^ - ((byte) 0x80 << 6) ^ - ((byte) 0x80 << 0)))); - if (isMalformed4(b2, b3, b4) || - // shortest form check - !Character.isSupplementaryCodePoint(uc)) { - if (malformedInputAction() != CodingErrorAction.REPLACE) - return -1; - da[dp++] = replacement().charAt(0); - sp -= 4; - bb = getByteBuffer(bb, sa, sp); - sp += malformedN(bb, 4).length(); - } else { - da[dp++] = Character.highSurrogate(uc); - da[dp++] = Character.lowSurrogate(uc); - } - continue; - } - if (malformedInputAction() != CodingErrorAction.REPLACE) - return -1; - b1 &= 0xff; - if (b1 > 0xf4 || - sp < sl && isMalformed4_2(b1, sa[sp] & 0xff)) { - da[dp++] = replacement().charAt(0); - continue; - } - sp++; - if (sp < sl && isMalformed4_3(sa[sp])) { - da[dp++] = replacement().charAt(0); - continue; - } - da[dp++] = replacement().charAt(0); - return dp; - } else { - if (malformedInputAction() != CodingErrorAction.REPLACE) - return -1; - da[dp++] = replacement().charAt(0); - } - } - return dp; - } - - public boolean isASCIICompatible() { - return true; - } } - private static final class Encoder extends CharsetEncoder - implements ArrayEncoder { + private static final class Encoder extends CharsetEncoder { private Encoder(Charset cs) { super(cs, 1.1f, 3.0f); @@ -699,58 +566,5 @@ return encodeBufferLoop(src, dst); } - private byte repl = (byte)'?'; - protected void implReplaceWith(byte[] newReplacement) { - repl = newReplacement[0]; - } - - // returns -1 if there is malformed char(s) and the - // "action" for malformed input is not REPLACE. - public int encode(char[] sa, int sp, int len, byte[] da) { - int sl = sp + len; - int dp = 0; - int dlASCII = dp + Math.min(len, da.length); - - // ASCII only optimized loop - while (dp < dlASCII && sa[sp] < '\u0080') - da[dp++] = (byte) sa[sp++]; - - while (sp < sl) { - char c = sa[sp++]; - if (c < 0x80) { - // Have at most seven bits - da[dp++] = (byte)c; - } else if (c < 0x800) { - // 2 bytes, 11 bits - da[dp++] = (byte)(0xc0 | (c >> 6)); - da[dp++] = (byte)(0x80 | (c & 0x3f)); - } else if (Character.isSurrogate(c)) { - if (sgp == null) - sgp = new Surrogate.Parser(); - int uc = sgp.parse(c, sa, sp - 1, sl); - if (uc < 0) { - if (malformedInputAction() != CodingErrorAction.REPLACE) - return -1; - da[dp++] = repl; - } else { - da[dp++] = (byte)(0xf0 | ((uc >> 18))); - da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f)); - da[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f)); - da[dp++] = (byte)(0x80 | (uc & 0x3f)); - sp++; // 2 chars - } - } else { - // 3 bytes, 16 bits - da[dp++] = (byte)(0xe0 | ((c >> 12))); - da[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f)); - da[dp++] = (byte)(0x80 | (c & 0x3f)); - } - } - return dp; - } - - public boolean isASCIICompatible() { - return true; - } } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/sun/util/cldr/CLDRCalendarDataProviderImpl.java Wed Dec 13 10:25:38 2017 -0800 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.cldr; + +import static sun.util.locale.provider.LocaleProviderAdapter.Type; + +import java.util.Arrays; +import java.util.Map; +import java.util.Locale; +import java.util.Set; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.LocaleResources; +import sun.util.locale.provider.CalendarDataProviderImpl; +import sun.util.locale.provider.CalendarDataUtility; + +/** + * Concrete implementation of the + * {@link java.util.spi.CalendarDataProvider CalendarDataProvider} class + * for the CLDR LocaleProviderAdapter. + * + * @author Naoto Sato + */ +public class CLDRCalendarDataProviderImpl extends CalendarDataProviderImpl { + + private static Map<String, Integer> firstDay = new ConcurrentHashMap<>(); + private static Map<String, Integer> minDays = new ConcurrentHashMap<>(); + + public CLDRCalendarDataProviderImpl(Type type, Set<String> langtags) { + super(type, langtags); + } + + @Override + public int getFirstDayOfWeek(Locale locale) { + return findValue(CalendarDataUtility.FIRST_DAY_OF_WEEK, locale); + } + + @Override + public int getMinimalDaysInFirstWeek(Locale locale) { + return findValue(CalendarDataUtility.MINIMAL_DAYS_IN_FIRST_WEEK, locale); + } + + /** + * Finds the requested integer value for the locale. + * Each resource consists of the following: + * + * (n: cc1 cc2 ... ccx;)* + * + * where 'n' is the integer for the following region codes, terminated by + * a ';'. + * + */ + private static int findValue(String key, Locale locale) { + Map<String, Integer> map = CalendarDataUtility.FIRST_DAY_OF_WEEK.equals(key) ? + firstDay : minDays; + String region = locale.getCountry(); + + if (region.isEmpty()) { + return 0; + } + + Integer val = map.get(region); + if (val == null) { + String valStr = + LocaleProviderAdapter.forType(Type.CLDR).getLocaleResources(Locale.ROOT) + .getCalendarData(key); + val = retrieveInteger(valStr, region) + .orElse(retrieveInteger(valStr, "001").orElse(0)); + map.putIfAbsent(region, val); + } + + return val; + } + + private static Optional<Integer> retrieveInteger(String src, String region) { + return Arrays.stream(src.split(";")) + .filter(entry -> entry.contains(region)) + .map(entry -> entry.substring(0, entry.indexOf(":"))) + .findAny() + .map(Integer::parseInt); + } +}
--- a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java Wed Dec 13 10:25:38 2017 -0800 @@ -27,6 +27,7 @@ import java.security.AccessController; import java.security.AccessControlException; +import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.text.spi.BreakIteratorProvider; @@ -37,15 +38,16 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Objects; +import java.util.Optional; import java.util.ServiceLoader; import java.util.ServiceConfigurationError; import java.util.Set; import java.util.StringTokenizer; import java.util.concurrent.ConcurrentHashMap; +import java.util.spi.CalendarDataProvider; import sun.util.locale.provider.JRELocaleProviderAdapter; +import sun.util.locale.provider.LocaleDataMetaInfo; import sun.util.locale.provider.LocaleProviderAdapter; -import sun.util.locale.provider.LocaleDataMetaInfo; /** * LocaleProviderAdapter implementation for the CLDR locale data. @@ -106,6 +108,24 @@ } @Override + public CalendarDataProvider getCalendarDataProvider() { + if (calendarDataProvider == null) { + CalendarDataProvider provider = AccessController.doPrivileged( + (PrivilegedAction<CalendarDataProvider>) () -> + new CLDRCalendarDataProviderImpl( + getAdapterType(), + getLanguageTagSet("CalendarData"))); + + synchronized (this) { + if (calendarDataProvider == null) { + calendarDataProvider = provider; + } + } + } + return calendarDataProvider; + } + + @Override public CollatorProvider getCollatorProvider() { return null; } @@ -123,6 +143,10 @@ @Override protected Set<String> createLanguageTagSet(String category) { + // Assume all categories support the same set as AvailableLocales + // in CLDR adapter. + category = "AvailableLocales"; + // Directly call Base tags, as we know it's in the base module. String supportedLocaleString = baseMetaInfo.availableLanguageTags(category); String nonBaseTags = null; @@ -220,4 +244,11 @@ || langtags.contains(locale.stripExtensions().toLanguageTag()) || langtags.contains(getEquivalentLoc(locale).toLanguageTag()); } + + /** + * Returns the time zone ID from an LDML's short ID + */ + public Optional<String> getTimeZoneID(String shortID) { + return Optional.ofNullable(baseMetaInfo.tzShortIDs().get(shortID)); + } }
--- a/src/java.base/share/classes/sun/util/locale/provider/CalendarDataProviderImpl.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/util/locale/provider/CalendarDataProviderImpl.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,14 +46,16 @@ @Override public int getFirstDayOfWeek(Locale locale) { - return LocaleProviderAdapter.forType(type).getLocaleResources(locale) + String fw = LocaleProviderAdapter.forType(type).getLocaleResources(locale) .getCalendarData(CalendarDataUtility.FIRST_DAY_OF_WEEK); + return convertToCalendarData(fw); } @Override public int getMinimalDaysInFirstWeek(Locale locale) { - return LocaleProviderAdapter.forType(type).getLocaleResources(locale) + String md = LocaleProviderAdapter.forType(type).getLocaleResources(locale) .getCalendarData(CalendarDataUtility.MINIMAL_DAYS_IN_FIRST_WEEK); + return convertToCalendarData(md); } @Override @@ -65,4 +67,9 @@ public Set<String> getAvailableLanguageTags() { return langtags; } + + private int convertToCalendarData(String src) { + int val = Integer.parseInt(src); + return (src.isEmpty() || val <= 0 || val > 7) ? 0 : val; + } }
--- a/src/java.base/share/classes/sun/util/locale/provider/CalendarDataUtility.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/util/locale/provider/CalendarDataUtility.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,10 +47,34 @@ } public static int retrieveFirstDayOfWeek(Locale locale) { + // Look for the Unicode Extension in the locale parameter + if (locale.hasExtensions()) { + String fw = locale.getUnicodeLocaleType("fw"); + if (fw != null) { + switch (fw.toLowerCase(Locale.ROOT)) { + case "mon": + return MONDAY; + case "tue": + return TUESDAY; + case "wed": + return WEDNESDAY; + case "thu": + return THURSDAY; + case "fri": + return FRIDAY; + case "sat": + return SATURDAY; + case "sun": + return SUNDAY; + } + } + } + LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(CalendarDataProvider.class); Integer value = pool.getLocalizedObject(CalendarWeekParameterGetter.INSTANCE, - locale, true, FIRST_DAY_OF_WEEK); + findRegionOverride(locale), + true, FIRST_DAY_OF_WEEK); return (value != null && (value >= SUNDAY && value <= SATURDAY)) ? value : SUNDAY; } @@ -58,7 +82,8 @@ LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(CalendarDataProvider.class); Integer value = pool.getLocalizedObject(CalendarWeekParameterGetter.INSTANCE, - locale, true, MINIMAL_DAYS_IN_FIRST_WEEK); + findRegionOverride(locale), + true, MINIMAL_DAYS_IN_FIRST_WEEK); return (value != null && (value >= 1 && value <= 7)) ? value : 1; } @@ -102,6 +127,32 @@ return map; } + /** + * Utility to look for a region override extension. + * If no region override is found, returns the original locale. + */ + public static Locale findRegionOverride(Locale l) { + String rg = l.getUnicodeLocaleType("rg"); + Locale override = l; + + if (rg != null && rg.length() == 6) { + // UN M.49 code should not be allowed here + // cannot use regex here, as it could be a recursive call + rg = rg.toUpperCase(Locale.ROOT); + if (rg.charAt(0) >= 0x0041 && + rg.charAt(0) <= 0x005A && + rg.charAt(1) >= 0x0041 && + rg.charAt(1) <= 0x005A && + rg.substring(2).equals("ZZZZ")) { + override = new Locale.Builder().setLocale(l) + .setRegion(rg.substring(0, 2)) + .build(); + } + } + + return override; + } + static String normalizeCalendarType(String requestID) { String type; if (requestID.equals("gregorian") || requestID.equals("iso8601")) { @@ -179,7 +230,7 @@ } } - private static class CalendarWeekParameterGetter + private static class CalendarWeekParameterGetter implements LocaleServiceProviderPool.LocalizedObjectGetter<CalendarDataProvider, Integer> { private static final CalendarWeekParameterGetter INSTANCE =
--- a/src/java.base/share/classes/sun/util/locale/provider/DateFormatProviderImpl.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/util/locale/provider/DateFormatProviderImpl.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.util.Locale; import java.util.MissingResourceException; import java.util.Set; +import java.util.TimeZone; /** * Concrete implementation of the {@link java.text.spi.DateFormatProvider @@ -147,11 +148,14 @@ throw new NullPointerException(); } - SimpleDateFormat sdf = new SimpleDateFormat("", locale); + // Check for region override + Locale rg = CalendarDataUtility.findRegionOverride(locale); + + SimpleDateFormat sdf = new SimpleDateFormat("", rg); Calendar cal = sdf.getCalendar(); try { String pattern = LocaleProviderAdapter.forType(type) - .getLocaleResources(locale).getDateTimePattern(timeStyle, dateStyle, + .getLocaleResources(rg).getDateTimePattern(timeStyle, dateStyle, cal); sdf.applyPattern(pattern); } catch (MissingResourceException mre) { @@ -159,6 +163,15 @@ sdf.applyPattern("M/d/yy h:mm a"); } + // Check for timezone override + String tz = locale.getUnicodeLocaleType("tz"); + if (tz != null) { + sdf.setTimeZone( + TimeZoneNameUtility.convertLDMLShortID(tz) + .map(TimeZone::getTimeZone) + .orElseGet(sdf::getTimeZone)); + } + return sdf; }
--- a/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,7 +130,7 @@ private volatile CurrencyNameProvider currencyNameProvider; private volatile LocaleNameProvider localeNameProvider; private volatile TimeZoneNameProvider timeZoneNameProvider; - private volatile CalendarDataProvider calendarDataProvider; + protected volatile CalendarDataProvider calendarDataProvider; private volatile CalendarNameProvider calendarNameProvider; private volatile CalendarProvider calendarProvider;
--- a/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package sun.util.locale.provider; +import java.util.Map; + /** * LocaleData meta info SPI * @@ -46,4 +48,13 @@ * @return concatenated language tags, separated by a space. */ public String availableLanguageTags(String category); + + /** + * Returns a map for short time zone ids in BCP47 Unicode extension and + * the long time zone ids. + * @return map of short id to long ids, separated by a space. + */ + default public Map<String, String> tzShortIDs() { + return null; + } }
--- a/src/java.base/share/classes/sun/util/locale/provider/LocaleNameProviderImpl.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleNameProviderImpl.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -168,6 +168,28 @@ return getDisplayString("%%"+vrnt, locale); } + /** + * @inheritDoc + */ + @Override + public String getDisplayUnicodeExtensionKey(String key, Locale locale) { + super.getDisplayUnicodeExtensionKey(key, locale); // null check + String rbKey = "key." + key; + String name = getDisplayString(rbKey, locale); + return rbKey.equals(name) ? key : name; + } + + /** + * @inheritDoc + */ + @Override + public String getDisplayUnicodeExtensionType(String extType, String key, Locale locale) { + super.getDisplayUnicodeExtensionType(extType, key, locale); // null check + String rbKey = "type." + key + "." + extType; + String name = getDisplayString(rbKey, locale); + return rbKey.equals(name) ? extType : name; + } + private String getDisplayString(String key, Locale locale) { if (key == null || locale == null) { throw new NullPointerException();
--- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,23 +122,21 @@ return (byte[]) localeData.getBreakIteratorResources(locale).getObject(key); } - int getCalendarData(String key) { - Integer caldata; + public String getCalendarData(String key) { + String caldata = ""; String cacheKey = CALENDAR_DATA + key; removeEmptyReferences(); ResourceReference data = cache.get(cacheKey); - if (data == null || ((caldata = (Integer) data.get()) == null)) { + if (data == null || ((caldata = (String) data.get()) == null)) { ResourceBundle rb = localeData.getCalendarData(locale); if (rb.containsKey(key)) { - caldata = Integer.parseInt(rb.getString(key)); - } else { - caldata = 0; + caldata = rb.getString(key); } cache.put(cacheKey, - new ResourceReference(cacheKey, (Object) caldata, referenceQueue)); + new ResourceReference(cacheKey, caldata, referenceQueue)); } return caldata;
--- a/src/java.base/share/classes/sun/util/locale/provider/NumberFormatProviderImpl.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/util/locale/provider/NumberFormatProviderImpl.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -173,9 +173,14 @@ throw new NullPointerException(); } + // Check for region override + Locale override = locale.getUnicodeLocaleType("nu") == null ? + CalendarDataUtility.findRegionOverride(locale) : + locale; + LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type); - String[] numberPatterns = adapter.getLocaleResources(locale).getNumberPatterns(); - DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale); + String[] numberPatterns = adapter.getLocaleResources(override).getNumberPatterns(); + DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(override); int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice; DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols);
--- a/src/java.base/share/classes/sun/util/locale/provider/SPILocaleProviderAdapter.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/util/locale/provider/SPILocaleProviderAdapter.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -160,28 +160,24 @@ @Override public BreakIterator getWordInstance(Locale locale) { BreakIteratorProvider bip = getImpl(locale); - assert bip != null; return bip.getWordInstance(locale); } @Override public BreakIterator getLineInstance(Locale locale) { BreakIteratorProvider bip = getImpl(locale); - assert bip != null; return bip.getLineInstance(locale); } @Override public BreakIterator getCharacterInstance(Locale locale) { BreakIteratorProvider bip = getImpl(locale); - assert bip != null; return bip.getCharacterInstance(locale); } @Override public BreakIterator getSentenceInstance(Locale locale) { BreakIteratorProvider bip = getImpl(locale); - assert bip != null; return bip.getSentenceInstance(locale); } @@ -215,7 +211,6 @@ @Override public Collator getInstance(Locale locale) { CollatorProvider cp = getImpl(locale); - assert cp != null; return cp.getInstance(locale); } } @@ -249,21 +244,18 @@ @Override public DateFormat getTimeInstance(int style, Locale locale) { DateFormatProvider dfp = getImpl(locale); - assert dfp != null; return dfp.getTimeInstance(style, locale); } @Override public DateFormat getDateInstance(int style, Locale locale) { DateFormatProvider dfp = getImpl(locale); - assert dfp != null; return dfp.getDateInstance(style, locale); } @Override public DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale locale) { DateFormatProvider dfp = getImpl(locale); - assert dfp != null; return dfp.getDateTimeInstance(dateStyle, timeStyle, locale); } } @@ -297,7 +289,6 @@ @Override public DateFormatSymbols getInstance(Locale locale) { DateFormatSymbolsProvider dfsp = getImpl(locale); - assert dfsp != null; return dfsp.getInstance(locale); } } @@ -331,7 +322,6 @@ @Override public DecimalFormatSymbols getInstance(Locale locale) { DecimalFormatSymbolsProvider dfsp = getImpl(locale); - assert dfsp != null; return dfsp.getInstance(locale); } } @@ -365,28 +355,24 @@ @Override public NumberFormat getCurrencyInstance(Locale locale) { NumberFormatProvider nfp = getImpl(locale); - assert nfp != null; return nfp.getCurrencyInstance(locale); } @Override public NumberFormat getIntegerInstance(Locale locale) { NumberFormatProvider nfp = getImpl(locale); - assert nfp != null; return nfp.getIntegerInstance(locale); } @Override public NumberFormat getNumberInstance(Locale locale) { NumberFormatProvider nfp = getImpl(locale); - assert nfp != null; return nfp.getNumberInstance(locale); } @Override public NumberFormat getPercentInstance(Locale locale) { NumberFormatProvider nfp = getImpl(locale); - assert nfp != null; return nfp.getPercentInstance(locale); } } @@ -420,14 +406,12 @@ @Override public int getFirstDayOfWeek(Locale locale) { CalendarDataProvider cdp = getImpl(locale); - assert cdp != null; return cdp.getFirstDayOfWeek(locale); } @Override public int getMinimalDaysInFirstWeek(Locale locale) { CalendarDataProvider cdp = getImpl(locale); - assert cdp != null; return cdp.getMinimalDaysInFirstWeek(locale); } } @@ -463,7 +447,6 @@ int field, int value, int style, Locale locale) { CalendarNameProvider cdp = getImpl(locale); - assert cdp != null; return cdp.getDisplayName(calendarType, field, value, style, locale); } @@ -472,7 +455,6 @@ int field, int style, Locale locale) { CalendarNameProvider cdp = getImpl(locale); - assert cdp != null; return cdp.getDisplayNames(calendarType, field, style, locale); } } @@ -506,14 +488,12 @@ @Override public String getSymbol(String currencyCode, Locale locale) { CurrencyNameProvider cnp = getImpl(locale); - assert cnp != null; return cnp.getSymbol(currencyCode, locale); } @Override public String getDisplayName(String currencyCode, Locale locale) { CurrencyNameProvider cnp = getImpl(locale); - assert cnp != null; return cnp.getDisplayName(currencyCode, locale); } } @@ -547,30 +527,38 @@ @Override public String getDisplayLanguage(String languageCode, Locale locale) { LocaleNameProvider lnp = getImpl(locale); - assert lnp != null; return lnp.getDisplayLanguage(languageCode, locale); } @Override public String getDisplayScript(String scriptCode, Locale locale) { LocaleNameProvider lnp = getImpl(locale); - assert lnp != null; return lnp.getDisplayScript(scriptCode, locale); } @Override public String getDisplayCountry(String countryCode, Locale locale) { LocaleNameProvider lnp = getImpl(locale); - assert lnp != null; return lnp.getDisplayCountry(countryCode, locale); } @Override public String getDisplayVariant(String variant, Locale locale) { LocaleNameProvider lnp = getImpl(locale); - assert lnp != null; return lnp.getDisplayVariant(variant, locale); } + + @Override + public String getDisplayUnicodeExtensionKey(String key, Locale locale) { + LocaleNameProvider lnp = getImpl(locale); + return lnp.getDisplayUnicodeExtensionKey(key, locale); + } + + @Override + public String getDisplayUnicodeExtensionType(String extType, String key, Locale locale) { + LocaleNameProvider lnp = getImpl(locale); + return lnp.getDisplayUnicodeExtensionType(extType, key, locale); + } } static class TimeZoneNameProviderDelegate extends TimeZoneNameProvider @@ -602,14 +590,12 @@ @Override public String getDisplayName(String ID, boolean daylight, int style, Locale locale) { TimeZoneNameProvider tznp = getImpl(locale); - assert tznp != null; return tznp.getDisplayName(ID, daylight, style, locale); } @Override public String getGenericDisplayName(String ID, int style, Locale locale) { TimeZoneNameProvider tznp = getImpl(locale); - assert tznp != null; return tznp.getGenericDisplayName(ID, style, locale); } }
--- a/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,10 +31,13 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.spi.TimeZoneNameProvider; import sun.util.calendar.ZoneInfo; +import sun.util.cldr.CLDRLocaleProviderAdapter; +import static sun.util.locale.provider.LocaleProviderAdapter.Type; /** * Utility class that deals with the localized time zone names @@ -152,6 +155,18 @@ } } + /** + * Converts the time zone id from LDML's 5-letter id to tzdb's id + * + * @param shortID time zone short ID defined in LDML + * @return the tzdb's time zone ID + */ + public static Optional<String> convertLDMLShortID(String shortID) { + return ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR)) + .getTimeZoneID(shortID) + .map(id -> id.replaceAll("\\s.*", "")); + } + private static String[] retrieveDisplayNamesImpl(String id, Locale locale) { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class);
--- a/src/java.base/share/classes/sun/util/resources/LocaleNames.properties Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/share/classes/sun/util/resources/LocaleNames.properties Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -1164,8 +1164,7 @@ # locale name patterns -# rarely localized DisplayNamePattern={0,choice,0#|1#{1}|2#{1} ({2})} -ListPattern={0,choice,0#|1#{1}|2#{1},{2}|3#{1},{2},{3}} +ListKeyTypePattern={0}:{1} ListCompositionPattern={0},{1}
--- a/src/java.base/windows/native/libnio/ch/SocketDispatcher.c Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.base/windows/native/libnio/ch/SocketDispatcher.c Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -179,7 +179,7 @@ } } - count += written; + count += (jint)written; address += written; } while ((count < total) && (written == MAX_BUFFER_SIZE));
--- a/src/java.xml/share/classes/org/w3c/dom/ls/DOMImplementationLS.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.xml/share/classes/org/w3c/dom/ls/DOMImplementationLS.java Wed Dec 13 10:25:38 2017 -0800 @@ -51,12 +51,13 @@ * binding-specific casting methods on an instance of the * <code>DOMImplementation</code> interface or, if the <code>Document</code> * supports the feature <code>"Core"</code> version <code>"3.0"</code> - * defined in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] + * defined in + * [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] * , by using the method <code>DOMImplementation.getFeature</code> with * parameter values <code>"LS"</code> (or <code>"LS-Async"</code>) and * <code>"3.0"</code> (respectively). - * <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>Document Object Model (DOM) Level 3 Load -and Save Specification</a>. + * <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'> +Document Object Model (DOM) Level 3 Load and Save Specification</a>. * * @since 1.5 */ @@ -90,9 +91,11 @@ * <code>LSParser</code> for any kind of schema types (i.e. the * LSParser will be free to use any schema found), use the value * <code>null</code>. - * <p ><b>Note:</b> For W3C XML Schema [<a href='http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/'>XML Schema Part 1</a>] + * <p ><b>Note:</b> For W3C XML Schema + * [<a href='http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/'>XML Schema Part 1</a>] * , applications must use the value - * <code>"http://www.w3.org/2001/XMLSchema"</code>. For XML DTD [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>], + * <code>"http://www.w3.org/2001/XMLSchema"</code>. For XML DTD + * [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>], * applications must use the value * <code>"http://www.w3.org/TR/REC-xml"</code>. Other Schema languages * are outside the scope of the W3C and therefore should recommend an @@ -102,8 +105,8 @@ * depending on the value of the <code>mode</code> argument. * <p ><b>Note:</b> By default, the newly created <code>LSParser</code> * does not contain a <code>DOMErrorHandler</code>, i.e. the value of - * the "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'> - * error-handler</a>" configuration parameter is <code>null</code>. However, implementations + * the "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>" + * configuration parameter is <code>null</code>. However, implementations * may provide a default error handler at creation time. In that case, * the initial value of the <code>"error-handler"</code> configuration * parameter on the new <code>LSParser</code> object contains a
--- a/src/java.xml/share/classes/org/w3c/dom/ls/LSParser.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.xml/share/classes/org/w3c/dom/ls/LSParser.java Wed Dec 13 10:25:38 2017 -0800 @@ -53,7 +53,8 @@ * corresponding DOM document structure. A <code>LSParser</code> instance * can be obtained by invoking the * <code>DOMImplementationLS.createLSParser()</code> method. - * <p> As specified in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] + * <p> As specified in + * [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] * , when a document is first made available via the LSParser: * <ul> * <li> there will @@ -63,16 +64,18 @@ * <li> it is expected that the <code>value</code> and * <code>nodeValue</code> attributes of an <code>Attr</code> node initially * return the <a href='http://www.w3.org/TR/2004/REC-xml-20040204#AVNormalize'>XML 1.0 - * normalized value</a>. However, if the parameters "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-validate-if-schema'> - * validate-if-schema</a>" and "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-datatype-normalization'> - * datatype-normalization</a>" are set to <code>true</code>, depending on the attribute normalization + * normalized value</a>. However, if the parameters + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-validate-if-schema'>validate-if-schema</a>" and + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-datatype-normalization'>datatype-normalization</a>" + * are set to <code>true</code>, depending on the attribute normalization * used, the attribute values may differ from the ones obtained by the XML - * 1.0 attribute normalization. If the parameters "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-datatype-normalization'> - * datatype-normalization</a>" is set to <code>false</code>, the XML 1.0 attribute normalization is + * 1.0 attribute normalization. If the parameters + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-datatype-normalization'>datatype-normalization</a>" + * is set to <code>false</code>, the XML 1.0 attribute normalization is * guaranteed to occur, and if the attributes list does not contain * namespace declarations, the <code>attributes</code> attribute on - * <code>Element</code> node represents the property <b>[attributes]</b> defined in [<a href='http://www.w3.org/TR/2004/REC-xml-infoset-20040204/'>XML Information Set</a>] - * . + * <code>Element</code> node represents the property <b>[attributes]</b> defined in + * [<a href='http://www.w3.org/TR/2004/REC-xml-infoset-20040204/'>XML Information Set</a>]. * </li> * </ul> * <p> Asynchronous <code>LSParser</code> objects are expected to also @@ -102,17 +105,18 @@ * <p ><b>Note:</b> All events defined in this specification use the * namespace URI <code>"http://www.w3.org/2002/DOMLS"</code>. * <p> While parsing an input source, errors are reported to the application - * through the error handler (<code>LSParser.domConfig</code>'s "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'> - * error-handler</a>" parameter). This specification does in no way try to define all possible + * through the error handler (<code>LSParser.domConfig</code>'s + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>" + * parameter). This specification does in no way try to define all possible * errors that can occur while parsing XML, or any other markup, but some * common error cases are defined. The types (<code>DOMError.type</code>) of * errors and warnings defined by this specification are: * <dl> * <dt> * <code>"check-character-normalization-failure" [error]</code> </dt> - * <dd> Raised if - * the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-check-character-normalization'> - * check-character-normalization</a>" is set to true and a string is encountered that fails normalization + * <dd> Raised if the parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-check-character-normalization'>check-character-normalization</a>" + * is set to true and a string is encountered that fails normalization * checking. </dd> * <dt><code>"doctype-not-allowed" [fatal]</code></dt> * <dd> Raised if the @@ -127,8 +131,9 @@ * <dd> Raised if a processing * instruction is encountered in a location where the base URI of the * processing instruction can not be preserved. One example of a case where - * this warning will be raised is if the configuration parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-entities'> - * entities</a>" is set to <code>false</code> and the following XML file is parsed: + * this warning will be raised is if the configuration parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-entities'>entities</a>" + * is set to <code>false</code> and the following XML file is parsed: * <pre> * <!DOCTYPE root [ <!ENTITY e SYSTEM 'subdir/myentity.ent' ]> * <root> &e; </root></pre> @@ -139,9 +144,9 @@ * </dd> * <dt><code>"unbound-prefix-in-entity" [warning]</code></dt> * <dd> An - * implementation dependent warning that may be raised if the configuration - * parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-namespaces'> - * namespaces</a>" is set to <code>true</code> and an unbound namespace prefix is + * implementation dependent warning that may be raised if the configuration parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-namespaces'>namespaces</a>" + * is set to <code>true</code> and an unbound namespace prefix is * encountered in an entity's replacement text. Raising this warning is not * enforced since some existing parsers may not recognize unbound namespace * prefixes in the replacement text of entities. </dd> @@ -164,8 +169,8 @@ * are expected to raise implementation specific errors and warnings for any * other error and warning cases such as IO errors (file not found, * permission denied,...), XML well-formedness errors, and so on. - * <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>Document Object Model (DOM) Level 3 Load -and Save Specification</a>. + * <p>See also the + * <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>Document Object Model (DOM) Level 3 Load and Save Specification</a>. * * @since 1.5 */ @@ -180,8 +185,10 @@ * needed parameter values from this <code>DOMConfiguration</code> * object to the <code>DOMConfiguration</code> object referenced by the * <code>Document</code> object. - * <br> In addition to the parameters recognized in on the <a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMConfiguration'> - * DOMConfiguration</a> interface defined in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] + * <br> In addition to the parameters recognized in on the + * <a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#DOMConfiguration'>DOMConfiguration</a> + * interface defined in + * [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] * , the <code>DOMConfiguration</code> objects for <code>LSParser</code> * add or modify the following parameters: * <dl> @@ -190,7 +197,8 @@ * <dd> * <dl> * <dt><code>true</code></dt> - * <dd>[<em>optional</em>] (<em>default</em>) If a higher level protocol such as HTTP [<a href='http://www.ietf.org/rfc/rfc2616.txt'>IETF RFC 2616</a>] provides an + * <dd>[<em>optional</em>] (<em>default</em>) If a higher level protocol such as HTTP + * [<a href='http://www.ietf.org/rfc/rfc2616.txt'>IETF RFC 2616</a>] provides an * indication of the character encoding of the input stream being * processed, that will override any encoding specified in the XML * declaration or the Text declaration (see also section 4.3.3, @@ -206,7 +214,8 @@ * <dl> * <dt> * <code>true</code></dt> - * <dd>[<em>optional</em>] Throw a fatal <b>"doctype-not-allowed"</b> error if a doctype node is found while parsing the document. This is + * <dd>[<em>optional</em>] Throw a fatal <b>"doctype-not-allowed"</b> error + * if a doctype node is found while parsing the document. This is * useful when dealing with things like SOAP envelopes where doctype * nodes are not allowed. </dd> * <dt><code>false</code></dt> @@ -218,14 +227,17 @@ * <dl> * <dt> * <code>true</code></dt> - * <dd>[<em>required</em>] (<em>default</em>) If, while verifying full normalization when [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>] is + * <dd>[<em>required</em>] (<em>default</em>) If, while verifying full normalization when + * [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>] is * supported, a processor encounters characters for which it cannot * determine the normalization properties, then the processor will * ignore any possible denormalizations caused by these characters. - * This parameter is ignored for [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>]. </dd> + * This parameter is ignored for [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>]. + * </dd> * <dt> * <code>false</code></dt> - * <dd>[<em>optional</em>] Report an fatal <b>"unknown-character-denormalization"</b> error if a character is encountered for which the processor cannot + * <dd>[<em>optional</em>] Report an fatal <b>"unknown-character-denormalization"</b> + * error if a character is encountered for which the processor cannot * determine the normalization properties. </dd> * </dl></dd> * <dt><code>"infoset"</code></dt> @@ -238,7 +250,8 @@ * <dd> * <dl> * <dt><code>true</code></dt> - * <dd>[<em>required</em>] (<em>default</em>) Perform the namespace processing as defined in [<a href='http://www.w3.org/TR/1999/REC-xml-names-19990114/'>XML Namespaces</a>] + * <dd>[<em>required</em>] (<em>default</em>) Perform the namespace processing as defined in + * [<a href='http://www.w3.org/TR/1999/REC-xml-names-19990114/'>XML Namespaces</a>] * and [<a href='http://www.w3.org/TR/2004/REC-xml-names11-20040204/'>XML Namespaces 1.1</a>] * . </dd> * <dt><code>false</code></dt> @@ -259,7 +272,8 @@ * <code>true</code></dt> * <dd>[<em>optional</em>] Check that the media type of the parsed resource is a supported media * type. If an unsupported media type is encountered, a fatal error of - * type <b>"unsupported-media-type"</b> will be raised. The media types defined in [<a href='http://www.ietf.org/rfc/rfc3023.txt'>IETF RFC 3023</a>] must always + * type <b>"unsupported-media-type"</b> will be raised. The media types defined in + * [<a href='http://www.ietf.org/rfc/rfc3023.txt'>IETF RFC 3023</a>] must always * be accepted. </dd> * <dt><code>false</code></dt> * <dd>[<em>required</em>] (<em>default</em>) Accept any media type. </dd> @@ -294,8 +308,8 @@ * terminate the parsing early. * <br> The filter is invoked after the operations requested by the * <code>DOMConfiguration</code> parameters have been applied. For - * example, if "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-validate'> - * validate</a>" is set to <code>true</code>, the validation is done before invoking the + * example, if "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-validate'>validate</a>" + * is set to <code>true</code>, the validation is done before invoking the * filter. */ public LSParserFilter getFilter(); @@ -306,8 +320,8 @@ * terminate the parsing early. * <br> The filter is invoked after the operations requested by the * <code>DOMConfiguration</code> parameters have been applied. For - * example, if "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-validate'> - * validate</a>" is set to <code>true</code>, the validation is done before invoking the + * example, if "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-validate'>validate</a>" + * is set to <code>true</code>, the validation is done before invoking the * filter. */ public void setFilter(LSParserFilter filter); @@ -340,15 +354,18 @@ * @exception LSException * PARSE_ERR: Raised if the <code>LSParser</code> was unable to load * the XML document. DOM applications should attach a - * <code>DOMErrorHandler</code> using the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'> - * error-handler</a>" if they wish to get details on the error. + * <code>DOMErrorHandler</code> using the parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>" + * if they wish to get details on the error. */ public Document parse(LSInput input) throws DOMException, LSException; /** - * Parse an XML document from a location identified by a URI reference [<a href='http://www.ietf.org/rfc/rfc2396.txt'>IETF RFC 2396</a>]. If the URI - * contains a fragment identifier (see section 4.1 in [<a href='http://www.ietf.org/rfc/rfc2396.txt'>IETF RFC 2396</a>]), the + * Parse an XML document from a location identified by a URI reference + * [<a href='http://www.ietf.org/rfc/rfc2396.txt'>IETF RFC 2396</a>]. If the URI + * contains a fragment identifier (see section 4.1 in + * [<a href='http://www.ietf.org/rfc/rfc2396.txt'>IETF RFC 2396</a>]), the * behavior is not defined by this specification, future versions of * this specification may define the behavior. * @param uri The location of the XML document to be read. @@ -364,8 +381,9 @@ * @exception LSException * PARSE_ERR: Raised if the <code>LSParser</code> was unable to load * the XML document. DOM applications should attach a - * <code>DOMErrorHandler</code> using the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'> - * error-handler</a>" if they wish to get details on the error. + * <code>DOMErrorHandler</code> using the parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>" + * if they wish to get details on the error. */ public Document parseURI(String uri) throws DOMException, LSException; @@ -431,14 +449,17 @@ * <code>LSParser</code> is asynchronous (<code>LSParser.async</code> is * <code>true</code>). * <br> If an error occurs while parsing, the caller is notified through - * the <code>ErrorHandler</code> instance associated with the "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'> - * error-handler</a>" parameter of the <code>DOMConfiguration</code>. + * the <code>ErrorHandler</code> instance associated with the + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>" + * parameter of the <code>DOMConfiguration</code>. * <br> When calling <code>parseWithContext</code>, the values of the * following configuration parameters will be ignored and their default - * values will always be used instead: "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-validate'> - * validate</a>", "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-validate-if-schema'> - * validate-if-schema</a>", and "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-element-content-whitespace'> - * element-content-whitespace</a>". Other parameters will be treated normally, and the parser is expected + * values will always be used instead: + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-validate'>validate</a>", + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-validate-if-schema'>validate-if-schema</a>", + * and + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-element-content-whitespace'>element-content-whitespace</a>". + * Other parameters will be treated normally, and the parser is expected * to call the <code>LSParserFilter</code> just as if a whole document * was parsed. * @param input The <code>LSInput</code> from which the source document @@ -463,7 +484,8 @@ * @exception DOMException * HIERARCHY_REQUEST_ERR: Raised if the content cannot replace, be * inserted before, after, or as a child of the context node (see also - * <code>Node.insertBefore</code> or <code>Node.replaceChild</code> in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] + * <code>Node.insertBefore</code> or <code>Node.replaceChild</code> in + * [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] * ). * <br> NOT_SUPPORTED_ERR: Raised if the <code>LSParser</code> doesn't * support this method, or if the context node is of type @@ -479,8 +501,9 @@ * @exception LSException * PARSE_ERR: Raised if the <code>LSParser</code> was unable to load * the XML fragment. DOM applications should attach a - * <code>DOMErrorHandler</code> using the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'> - * error-handler</a>" if they wish to get details on the error. + * <code>DOMErrorHandler</code> using the parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>" + * if they wish to get details on the error. */ public Node parseWithContext(LSInput input, Node contextArg,
--- a/src/java.xml/share/classes/org/w3c/dom/ls/LSParserFilter.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.xml/share/classes/org/w3c/dom/ls/LSParserFilter.java Wed Dec 13 10:25:38 2017 -0800 @@ -56,10 +56,11 @@ * <code>Document</code>, <code>DocumentType</code>, <code>Notation</code>, * <code>Entity</code>, and <code>Attr</code> nodes are never passed to the * <code>acceptNode</code> method on the filter. The child nodes of an - * <code>EntityReference</code> node are passed to the filter if the - * parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-entities'> - * entities</a>" is set to <code>false</code>. Note that, as described by the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-entities'> - * entities</a>", unexpanded entity reference nodes are never discarded and are always + * <code>EntityReference</code> node are passed to the filter if the parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-entities'>entities</a>" + * is set to <code>false</code>. Note that, as described by the parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-entities'>entities</a>", + * unexpanded entity reference nodes are never discarded and are always * passed to the filter. * <p> All validity checking while parsing a document occurs on the source * document as it appears on the input stream, not on the DOM document as it @@ -71,8 +72,8 @@ * passed to the filter methods. * <p> DOM applications must not raise exceptions in a filter. The effect of * throwing exceptions from a filter is DOM implementation dependent. - * <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>Document Object Model (DOM) Level 3 Load -and Save Specification</a>. + * <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'> +Document Object Model (DOM) Level 3 Load and Save Specification</a>. * * @since 1.5 */ @@ -195,8 +196,8 @@ * <code>SHOW_NOTATION</code>, <code>SHOW_ENTITY</code>, and * <code>SHOW_DOCUMENT_FRAGMENT</code> are meaningless here. Those nodes * will never be passed to <code>LSParserFilter.acceptNode</code>. - * <br> The constants used here are defined in [<a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>DOM Level 2 Traversal and Range</a>] - * . + * <br> The constants used here are defined in + * [<a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>DOM Level 2 Traversal and Range</a>]. */ public int getWhatToShow();
--- a/src/java.xml/share/classes/org/w3c/dom/ls/LSSerializer.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/java.xml/share/classes/org/w3c/dom/ls/LSSerializer.java Wed Dec 13 10:25:38 2017 -0800 @@ -51,7 +51,8 @@ * output stream. Any changes or fixups made during the serialization affect * only the serialized data. The <code>Document</code> object and its * children are never altered by the serialization operation. - * <p> During serialization of XML data, namespace fixup is done as defined in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] + * <p> During serialization of XML data, namespace fixup is done as defined in + * [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] * , Appendix B. [<a href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113'>DOM Level 2 Core</a>] * allows empty strings as a real namespace URI. If the * <code>namespaceURI</code> of a <code>Node</code> is empty string, the @@ -80,12 +81,14 @@ * namespace fixup is done. The resulting output will be valid as an * external entity. * </li> - * <li> If the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-entities'> - * entities</a>" is set to <code>true</code>, <code>EntityReference</code> nodes are + * <li> If the parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-entities'>entities</a>" + * is set to <code>true</code>, <code>EntityReference</code> nodes are * serialized as an entity reference of the form " * <code>&entityName;</code>" in the output. Child nodes (the expansion) - * of the entity reference are ignored. If the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-entities'> - * entities</a>" is set to <code>false</code>, only the children of the entity reference + * of the entity reference are ignored. If the parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-entities'>entities</a>" + * is set to <code>false</code>, only the children of the entity reference * are serialized. <code>EntityReference</code> nodes with no children (no * corresponding <code>Entity</code> node or the corresponding * <code>Entity</code> nodes have no children) are always serialized. @@ -93,15 +96,16 @@ * <li> * <code>CDATAsections</code> containing content characters that cannot be * represented in the specified output encoding are handled according to the - * "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-split-cdata-sections'> - * split-cdata-sections</a>" parameter. If the parameter is set to <code>true</code>, + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-split-cdata-sections'>split-cdata-sections</a>" + * parameter. If the parameter is set to <code>true</code>, * <code>CDATAsections</code> are split, and the unrepresentable characters * are serialized as numeric character references in ordinary content. The * exact position and number of splits is not specified. If the parameter * is set to <code>false</code>, unrepresentable characters in a * <code>CDATAsection</code> are reported as - * <code>"wf-invalid-character"</code> errors if the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-well-formed'> - * well-formed</a>" is set to <code>true</code>. The error is not recoverable - there is no + * <code>"wf-invalid-character"</code> errors if the parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-well-formed'>well-formed</a>" + * is set to <code>true</code>. The error is not recoverable - there is no * mechanism for supplying alternative characters and continuing with the * serialization. * </li> @@ -138,12 +142,15 @@ * as a <code>DOMError</code> fatal error. An example would be serializing * the element <LaCañada/> with <code>encoding="us-ascii"</code>. * This will result with a generation of a <code>DOMError</code> - * "wf-invalid-character-in-node-name" (as proposed in "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-well-formed'> - * well-formed</a>"). - * <p> When requested by setting the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-normalize-characters'> - * normalize-characters</a>" on <code>LSSerializer</code> to true, character normalization is - * performed according to the definition of <a href='http://www.w3.org/TR/2004/REC-xml11-20040204/#dt-fullnorm'>fully - * normalized</a> characters included in appendix E of [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>] on all + * "wf-invalid-character-in-node-name" (as proposed in + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-well-formed'>well-formed</a>"). + * <p> When requested by setting the parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-normalize-characters'>normalize-characters</a>" + * on <code>LSSerializer</code> to true, character normalization is + * performed according to the definition of + * <a href='http://www.w3.org/TR/2004/REC-xml11-20040204/#dt-fullnorm'>fully + * normalized</a> characters included in appendix E of + * [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>] on all * data to be serialized, both markup and character data. The character * normalization process affects only the data as it is being written; it * does not alter the DOM's view of the document after serialization has @@ -170,13 +177,15 @@ * inconsistencies are found, the serialized form of the document will be * altered to remove them. The method used for doing the namespace fixup * while serializing a document is the algorithm defined in Appendix B.1, - * "Namespace normalization", of [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] + * "Namespace normalization", of + * [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] * . * <p> While serializing a document, the parameter "discard-default-content" * controls whether or not non-specified data is serialized. * <p> While serializing, errors and warnings are reported to the application - * through the error handler (<code>LSSerializer.domConfig</code>'s "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'> - * error-handler</a>" parameter). This specification does in no way try to define all possible + * through the error handler (<code>LSSerializer.domConfig</code>'s + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>" + * parameter). This specification does in no way try to define all possible * errors and warnings that can occur while serializing a DOM node, but some * common error and warning cases are defined. The types ( * <code>DOMError.type</code>) of errors and warnings defined by this @@ -189,8 +198,9 @@ * <dt> * <code>"unbound-prefix-in-entity-reference" [fatal]</code> </dt> * <dd> Raised if the - * configuration parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-namespaces'> - * namespaces</a>" is set to <code>true</code> and an entity whose replacement text + * configuration parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-namespaces'>namespaces</a>" + * is set to <code>true</code> and an entity whose replacement text * contains unbound namespace prefixes is referenced in a location where * there are no bindings for the namespace prefixes. </dd> * <dt> @@ -202,8 +212,9 @@ * are expected to raise implementation specific errors and warnings for any * other error and warning cases such as IO errors (file not found, * permission denied,...) and so on. - * <p>See also the <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'>Document Object Model (DOM) Level 3 Load -and Save Specification</a>. + * <p>See also the + * <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407'> +Document Object Model (DOM) Level 3 Load and Save Specification</a>. * * @since 1.5 */ @@ -211,8 +222,10 @@ /** * The <code>DOMConfiguration</code> object used by the * <code>LSSerializer</code> when serializing a DOM node. - * <br> In addition to the parameters recognized by the <a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMConfiguration'> - * DOMConfiguration</a> interface defined in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] + * <br> In addition to the parameters recognized by the + * <a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#DOMConfiguration'>DOMConfiguration</a> + * interface defined in + * [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] * , the <code>DOMConfiguration</code> objects for * <code>LSSerializer</code> adds, or modifies, the following * parameters: @@ -221,9 +234,11 @@ * <dd> * <dl> * <dt><code>true</code></dt> - * <dd>[<em>optional</em>] Writes the document according to the rules specified in [<a href='http://www.w3.org/TR/2001/REC-xml-c14n-20010315'>Canonical XML</a>]. - * In addition to the behavior described in "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-canonical-form'> - * canonical-form</a>" [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] + * <dd>[<em>optional</em>] Writes the document according to the rules specified in + * [<a href='http://www.w3.org/TR/2001/REC-xml-c14n-20010315'>Canonical XML</a>]. + * In addition to the behavior described in + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-canonical-form'>canonical-form</a>" + * [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] * , setting this parameter to <code>true</code> will set the parameters * "format-pretty-print", "discard-default-content", and "xml-declaration * ", to <code>false</code>. Setting one of those parameters to @@ -267,7 +282,8 @@ * <dl> * <dt> * <code>true</code></dt> - * <dd>[<em>required</em>] (<em>default</em>) If, while verifying full normalization when [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>] is + * <dd>[<em>required</em>] (<em>default</em>) If, while verifying full normalization when + * [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>] is * supported, a character is encountered for which the normalization * properties cannot be determined, then raise a * <code>"unknown-character-denormalization"</code> warning (instead of @@ -281,18 +297,21 @@ * <dt> * <code>"normalize-characters"</code></dt> * <dd> This parameter is equivalent to - * the one defined by <code>DOMConfiguration</code> in [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] + * the one defined by <code>DOMConfiguration</code> in + * [<a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407'>DOM Level 3 Core</a>] * . Unlike in the Core, the default value for this parameter is * <code>true</code>. While DOM implementations are not required to * support <a href='http://www.w3.org/TR/2004/REC-xml11-20040204/#dt-fullnorm'>fully - * normalizing</a> the characters in the document according to appendix E of [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>], this + * normalizing</a> the characters in the document according to appendix E of + * [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>], this * parameter must be activated by default if supported. </dd> * <dt> * <code>"xml-declaration"</code></dt> * <dd> * <dl> * <dt><code>true</code></dt> - * <dd>[<em>required</em>] (<em>default</em>) If a <code>Document</code>, <code>Element</code>, or <code>Entity</code> + * <dd>[<em>required</em>] (<em>default</em>) If a <code>Document</code>, + * <code>Element</code>, or <code>Entity</code> * node is serialized, the XML declaration, or text declaration, should * be included. The version (<code>Document.xmlVersion</code> if the * document is a Level 3 document and the version is non-null, otherwise @@ -303,7 +322,8 @@ * <code>false</code></dt> * <dd>[<em>required</em>] Do not serialize the XML and text declarations. Report a * <code>"xml-declaration-needed"</code> warning if this will cause - * problems (i.e. the serialized data is of an XML version other than [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>], or an + * problems (i.e. the serialized data is of an XML version other than + * [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>], or an * encoding would be needed to be able to re-parse the serialized data). </dd> * </dl></dd> * </dl> @@ -314,8 +334,8 @@ * The end-of-line sequence of characters to be used in the XML being * written out. Any string is supported, but XML treats only a certain * set of characters sequence as end-of-line (See section 2.11, - * "End-of-Line Handling" in [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>], if the - * serialized content is XML 1.0 or section 2.11, "End-of-Line Handling" + * "End-of-Line Handling" in [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>], + * if the serialized content is XML 1.0 or section 2.11, "End-of-Line Handling" * in [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>], if the * serialized content is XML 1.1). Using other character sequences than * the recommended ones can result in a document that is either not @@ -335,8 +355,8 @@ * The end-of-line sequence of characters to be used in the XML being * written out. Any string is supported, but XML treats only a certain * set of characters sequence as end-of-line (See section 2.11, - * "End-of-Line Handling" in [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>], if the - * serialized content is XML 1.0 or section 2.11, "End-of-Line Handling" + * "End-of-Line Handling" in [<a href='http://www.w3.org/TR/2004/REC-xml-20040204'>XML 1.0</a>], + * if the serialized content is XML 1.0 or section 2.11, "End-of-Line Handling" * in [<a href='http://www.w3.org/TR/2004/REC-xml11-20040204/'>XML 1.1</a>], if the * serialized content is XML 1.1). Using other character sequences than * the recommended ones can result in a document that is either not @@ -360,8 +380,9 @@ * serialization early. * <br> The filter is invoked after the operations requested by the * <code>DOMConfiguration</code> parameters have been applied. For - * example, CDATA sections won't be passed to the filter if "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-cdata-sections'> - * cdata-sections</a>" is set to <code>false</code>. + * example, CDATA sections won't be passed to the filter if + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-cdata-sections'>cdata-sections</a>" + * is set to <code>false</code>. */ public LSSerializerFilter getFilter(); /** @@ -371,8 +392,9 @@ * serialization early. * <br> The filter is invoked after the operations requested by the * <code>DOMConfiguration</code> parameters have been applied. For - * example, CDATA sections won't be passed to the filter if "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-cdata-sections'> - * cdata-sections</a>" is set to <code>false</code>. + * example, CDATA sections won't be passed to the filter if + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-cdata-sections'>cdata-sections</a>" + * is set to <code>false</code>. */ public void setFilter(LSSerializerFilter filter); @@ -414,8 +436,9 @@ * @exception LSException * SERIALIZE_ERR: Raised if the <code>LSSerializer</code> was unable to * serialize the node. DOM applications should attach a - * <code>DOMErrorHandler</code> using the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'> - * error-handler</a>" if they wish to get details on the error. + * <code>DOMErrorHandler</code> using the parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>" + * if they wish to get details on the error. */ public boolean write(Node nodeArg, LSOutput destination) @@ -436,8 +459,9 @@ * @exception LSException * SERIALIZE_ERR: Raised if the <code>LSSerializer</code> was unable to * serialize the node. DOM applications should attach a - * <code>DOMErrorHandler</code> using the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'> - * error-handler</a>" if they wish to get details on the error. + * <code>DOMErrorHandler</code> using the parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>" + * if they wish to get details on the error. */ public boolean writeToURI(Node nodeArg, String uri) @@ -458,8 +482,9 @@ * @exception LSException * SERIALIZE_ERR: Raised if the <code>LSSerializer</code> was unable to * serialize the node. DOM applications should attach a - * <code>DOMErrorHandler</code> using the parameter "<a href='http://www.w3.org/TR/DOM-Level-3-Core/core.html#parameter-error-handler'> - * error-handler</a>" if they wish to get details on the error. + * <code>DOMErrorHandler</code> using the parameter + * "<a href='https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#parameter-error-handler'>error-handler</a>" + * if they wish to get details on the error. */ public String writeToString(Node nodeArg) throws DOMException, LSException;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Wed Dec 13 10:25:38 2017 -0800 @@ -4238,9 +4238,6 @@ public void visitTypeArray(JCArrayTypeTree tree) { Type etype = attribType(tree.elemtype, env); Type type = new ArrayType(etype, syms.arrayClass); - if (etype.isErroneous()) { - type = types.createErrorType(type); - } result = check(tree, type, KindSelector.TYP, resultInfo); }
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Secmod.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Secmod.java Wed Dec 13 10:25:38 2017 -0800 @@ -196,13 +196,23 @@ } if (configDir != null) { - File configBase = new File(configDir); + String configDirPath = null; + String sqlPrefix = "sql:/"; + if (!configDir.startsWith(sqlPrefix)) { + configDirPath = configDir; + } else { + StringBuilder configDirPathSB = new StringBuilder(configDir); + configDirPath = configDirPathSB.substring(sqlPrefix.length()); + } + File configBase = new File(configDirPath); if (configBase.isDirectory() == false ) { - throw new IOException("configDir must be a directory: " + configDir); + throw new IOException("configDir must be a directory: " + configDirPath); } - File secmodFile = new File(configBase, "secmod.db"); - if (secmodFile.isFile() == false) { - throw new FileNotFoundException(secmodFile.getPath()); + if (!configDir.startsWith(sqlPrefix)) { + File secmodFile = new File(configBase, "secmod.db"); + if (secmodFile.isFile() == false) { + throw new FileNotFoundException(secmodFile.getPath()); + } } }
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java Wed Dec 13 10:25:38 2017 -0800 @@ -111,6 +111,15 @@ */ SET, /** + * Removes the value from a namespace defined on an object. Call sites with this + * operation should have a signature of + * <code>(receiver, name)→void</code> or + * <code>(receiver)→void</code> when used with {@link NamedOperation}, + * with all parameters being of any type (either primitive + * or reference). This operation must always be used as part of a {@link NamespaceOperation}. + */ + REMOVE, + /** * Call a callable object. Call sites with this operation should have a * signature of <code>(callable, receiver, arguments...)→value</code>, * with all parameters and return type being of any type (either primitive or
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java Wed Dec 13 10:25:38 2017 -0800 @@ -107,7 +107,8 @@ /** * A class that provides linking capabilities for a single POJO class. Normally not used directly, but managed by - * {@link BeansLinker}. + * {@link BeansLinker}. Most of the functionality is provided by the {@link AbstractJavaLinker} superclass; this + * class adds length and element operations for arrays and collections. */ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicLinker { BeanLinker(final Class<?> clazz) { @@ -147,6 +148,8 @@ return getElementGetter(req.popNamespace()); } else if (op == StandardOperation.SET) { return getElementSetter(req.popNamespace()); + } else if (op == StandardOperation.REMOVE) { + return getElementRemover(req.popNamespace()); } } } @@ -228,7 +231,7 @@ // dealing with an array, or a list or map, but hey... // Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers // in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices. - if(declaredType.isArray()) { + if(declaredType.isArray() && arrayMethod != null) { return new GuardedInvocationComponentAndCollectionType( createInternalFilteredGuardedInvocationComponent(arrayMethod.apply(declaredType), linkerServices), CollectionType.ARRAY); @@ -240,7 +243,7 @@ return new GuardedInvocationComponentAndCollectionType( createInternalFilteredGuardedInvocationComponent(mapMethod, linkerServices), CollectionType.MAP); - } else if(clazz.isArray()) { + } else if(clazz.isArray() && arrayMethod != null) { return new GuardedInvocationComponentAndCollectionType( getClassGuardedInvocationComponent(linkerServices.filterInternalObjects(arrayMethod.apply(clazz)), callSiteType), CollectionType.ARRAY); @@ -450,7 +453,7 @@ } @SuppressWarnings("unused") - private static void noOpSetter() { + private static void noOp() { } private static final MethodHandle SET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "set", @@ -459,12 +462,14 @@ private static final MethodHandle PUT_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "put", MethodType.methodType(Object.class, Object.class, Object.class)); - private static final MethodHandle NO_OP_SETTER_2; - private static final MethodHandle NO_OP_SETTER_3; + private static final MethodHandle NO_OP_1; + private static final MethodHandle NO_OP_2; + private static final MethodHandle NO_OP_3; static { - final MethodHandle noOpSetter = Lookup.findOwnStatic(MethodHandles.lookup(), "noOpSetter", void.class); - NO_OP_SETTER_2 = dropObjectArguments(noOpSetter, 2); - NO_OP_SETTER_3 = dropObjectArguments(noOpSetter, 3); + final MethodHandle noOp = Lookup.findOwnStatic(MethodHandles.lookup(), "noOp", void.class); + NO_OP_1 = dropObjectArguments(noOp, 1); + NO_OP_2 = dropObjectArguments(noOp, 2); + NO_OP_3 = dropObjectArguments(noOp, 3); } private GuardedInvocationComponent getElementSetter(final ComponentLinkRequest req) throws Exception { @@ -503,7 +508,39 @@ return gic.replaceInvocation(binder.bind(invocation)); } - return guardComponentWithRangeCheck(gicact, callSiteType, nextComponent, binder, isFixedKey ? NO_OP_SETTER_2 : NO_OP_SETTER_3); + return guardComponentWithRangeCheck(gicact, callSiteType, nextComponent, binder, isFixedKey ? NO_OP_2 : NO_OP_3); + } + + private static final MethodHandle REMOVE_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "remove", + MethodType.methodType(Object.class, int.class)); + + private static final MethodHandle REMOVE_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "remove", + MethodType.methodType(Object.class, Object.class)); + + private GuardedInvocationComponent getElementRemover(final ComponentLinkRequest req) throws Exception { + final CallSiteDescriptor callSiteDescriptor = req.getDescriptor(); + final Object name = req.name; + final boolean isFixedKey = name != null; + assertParameterCount(callSiteDescriptor, isFixedKey ? 1 : 2); + final LinkerServices linkerServices = req.linkerServices; + final MethodType callSiteType = callSiteDescriptor.getMethodType(); + final GuardedInvocationComponent nextComponent = getNextComponent(req); + + final GuardedInvocationComponentAndCollectionType gicact = guardedInvocationComponentAndCollectionType( + callSiteType, linkerServices, null, REMOVE_LIST_ELEMENT, REMOVE_MAP_ELEMENT); + + if (gicact == null) { + // Can't remove elements for objects that are neither lists, nor maps. + return nextComponent; + } + + final Object typedName = getTypedName(name, gicact.collectionType == CollectionType.MAP, linkerServices); + if (typedName == INVALID_NAME) { + return nextComponent; + } + + return guardComponentWithRangeCheck(gicact, callSiteType, nextComponent, + new Binder(linkerServices, callSiteType, typedName), isFixedKey ? NO_OP_1: NO_OP_2); } private static final MethodHandle GET_COLLECTION_LENGTH = Lookup.PUBLIC.findVirtual(Collection.class, "size",
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java Wed Dec 13 10:25:38 2017 -0800 @@ -113,6 +113,8 @@ * <li> expose elements of native Java arrays, {@link java.util.List} and {@link java.util.Map} objects as * {@link StandardOperation#GET} and {@link StandardOperation#SET} operations in the * {@link StandardNamespace#ELEMENT} namespace;</li> + * <li> expose removal of elements of {@link java.util.List} and {@link java.util.Map} objects as + * {@link StandardOperation#REMOVE} operation in the {@link StandardNamespace#ELEMENT} namespace;</li> * <li>expose a virtual property named {@code length} on Java arrays, {@link java.util.Collection} and * {@link java.util.Map} objects;</li> * <li>expose {@link StandardOperation#NEW} on instances of {@link StaticClass}
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java Wed Dec 13 10:25:38 2017 -0800 @@ -128,6 +128,9 @@ /** Returns List<MonitorInfo> */ public List<MonitorInfo> getMonitors() { + if (getScope() == null) { + return new ArrayList<>(); + } List monitors = getScope().getMonitors(); if (monitors == null) { return new ArrayList<>();
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/Http2ClientImpl.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/Http2ClientImpl.java Wed Dec 13 10:25:38 2017 -0800 @@ -36,6 +36,8 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CompletableFuture; + +import jdk.incubator.http.internal.common.Log; import jdk.incubator.http.internal.common.MinimalFuture; import jdk.incubator.http.internal.common.Utils; import jdk.incubator.http.internal.frame.SettingsFrame; @@ -78,10 +80,6 @@ } } -// boolean haveConnectionFor(URI uri, InetSocketAddress proxy) { -// return connections.containsKey(Http2Connection.keyFor(uri,proxy)); -// } - /** * If a https request then async waits until a connection is opened. * Returns null if the request is 'http' as a different (upgrade) @@ -188,18 +186,64 @@ private static final int K = 1024; + private static int getParameter(String property, int min, int max, int defaultValue) { + int value = Utils.getIntegerNetProperty(property, defaultValue); + // use default value if misconfigured + if (value < min || value > max) { + Log.logError("Property value for {0}={1} not in [{2}..{3}]: " + + "using default={4}", property, value, min, max, defaultValue); + value = defaultValue; + } + return value; + } + + // used for the connection window, to have a connection window size + // bigger than the initial stream window size. + int getConnectionWindowSize(SettingsFrame clientSettings) { + // Maximum size is 2^31-1. Don't allow window size to be less + // than the stream window size. HTTP/2 specify a default of 64 * K -1, + // but we use 2^26 by default for better performance. + int streamWindow = clientSettings.getParameter(INITIAL_WINDOW_SIZE); + + // The default is the max between the stream window size + // and the connection window size. + int defaultValue = Math.min(Integer.MAX_VALUE, + Math.max(streamWindow, K*K*32)); + + return getParameter( + "jdk.httpclient.connectionWindowSize", + streamWindow, Integer.MAX_VALUE, defaultValue); + } + SettingsFrame getClientSettings() { SettingsFrame frame = new SettingsFrame(); - frame.setParameter(HEADER_TABLE_SIZE, Utils.getIntegerNetProperty( - "jdk.httpclient.hpack.maxheadertablesize", 16 * K)); - frame.setParameter(ENABLE_PUSH, Utils.getIntegerNetProperty( - "jdk.httpclient.enablepush", 1)); - frame.setParameter(MAX_CONCURRENT_STREAMS, Utils.getIntegerNetProperty( - "jdk.httpclient.maxstreams", 16)); - frame.setParameter(INITIAL_WINDOW_SIZE, Utils.getIntegerNetProperty( - "jdk.httpclient.windowsize", 64 * K - 1)); - frame.setParameter(MAX_FRAME_SIZE, Utils.getIntegerNetProperty( - "jdk.httpclient.maxframesize", 16 * K)); + // default defined for HTTP/2 is 4 K, we use 16 K. + frame.setParameter(HEADER_TABLE_SIZE, getParameter( + "jdk.httpclient.hpack.maxheadertablesize", + 0, Integer.MAX_VALUE, 16 * K)); + // O: does not accept push streams. 1: accepts push streams. + frame.setParameter(ENABLE_PUSH, getParameter( + "jdk.httpclient.enablepush", + 0, 1, 1)); + // HTTP/2 recommends to set the number of concurrent streams + // no lower than 100. We use 100. 0 means no stream would be + // accepted. That would render the client to be non functional, + // so we won't let 0 be configured for our Http2ClientImpl. + frame.setParameter(MAX_CONCURRENT_STREAMS, getParameter( + "jdk.httpclient.maxstreams", + 1, Integer.MAX_VALUE, 100)); + // Maximum size is 2^31-1. Don't allow window size to be less + // than the minimum frame size as this is likely to be a + // configuration error. HTTP/2 specify a default of 64 * K -1, + // but we use 16 M for better performance. + frame.setParameter(INITIAL_WINDOW_SIZE, getParameter( + "jdk.httpclient.windowsize", + 16 * K, Integer.MAX_VALUE, 16*K*K)); + // HTTP/2 specify a minimum size of 16 K, a maximum size of 2^24-1, + // and a default of 16 K. We use 16 K as default. + frame.setParameter(MAX_FRAME_SIZE, getParameter( + "jdk.httpclient.maxframesize", + 16 * K, 16 * K * K -1, 16 * K)); return frame; } }
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/Http2Connection.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/Http2Connection.java Wed Dec 13 10:25:38 2017 -0800 @@ -228,7 +228,7 @@ private final WindowController windowController = new WindowController(); private final FramesController framesController = new FramesController(); private final Http2TubeSubscriber subscriber = new Http2TubeSubscriber(); - final WindowUpdateSender windowUpdater; + final ConnectionWindowUpdateSender windowUpdater; private volatile Throwable cause; private volatile Supplier<ByteBuffer> initial; @@ -247,7 +247,8 @@ this.nextstreamid = nextstreamid; this.key = key; this.clientSettings = this.client2.getClientSettings(); - this.framesDecoder = new FramesDecoder(this::processFrame, clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE)); + this.framesDecoder = new FramesDecoder(this::processFrame, + clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE)); // serverSettings will be updated by server this.serverSettings = SettingsFrame.getDefaultSettings(); this.hpackOut = new Encoder(serverSettings.getParameter(HEADER_TABLE_SIZE)); @@ -255,7 +256,8 @@ debugHpack.log(Level.DEBUG, () -> "For the record:" + super.toString()); debugHpack.log(Level.DEBUG, "Decoder created: %s", hpackIn); debugHpack.log(Level.DEBUG, "Encoder created: %s", hpackOut); - this.windowUpdater = new ConnectionWindowUpdateSender(this, client().getReceiveBufferSize()); + this.windowUpdater = new ConnectionWindowUpdateSender(this, + client2.getConnectionWindowSize(clientSettings)); } /** @@ -774,7 +776,8 @@ Log.logTrace("{0}: start sending connection preface to {1}", connection.channel().getLocalAddress(), connection.address()); - SettingsFrame sf = client2.getClientSettings(); + SettingsFrame sf = new SettingsFrame(clientSettings); + int initialWindowSize = sf.getParameter(INITIAL_WINDOW_SIZE); ByteBuffer buf = framesEncoder.encodeConnectionPreface(PREFACE_BYTES, sf); Log.logFrames(sf, "OUT"); // send preface bytes and SettingsFrame together @@ -788,8 +791,10 @@ // send a Window update for the receive buffer we are using // minus the initial 64 K specified in protocol - final int len = client2.client().getReceiveBufferSize() - (64 * 1024 - 1); - windowUpdater.sendWindowUpdate(len); + final int len = windowUpdater.initialWindowSize - initialWindowSize; + if (len > 0) { + windowUpdater.sendWindowUpdate(len); + } // there will be an ACK to the windows update - which should // cause any pending data stored before the preface was sent to be // flushed (see PrefaceController). @@ -1202,9 +1207,11 @@ static final class ConnectionWindowUpdateSender extends WindowUpdateSender { + final int initialWindowSize; public ConnectionWindowUpdateSender(Http2Connection connection, int initialWindowSize) { super(connection, initialWindowSize); + this.initialWindowSize = initialWindowSize; } @Override
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpClientImpl.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpClientImpl.java Wed Dec 13 10:25:38 2017 -0800 @@ -1038,7 +1038,7 @@ // used for the connection window int getReceiveBufferSize() { return Utils.getIntegerNetProperty( - "jdk.httpclient.connectionWindowSize", 256 * 1024 + "jdk.httpclient.receiveBufferSize", 2 * 1024 * 1024 ); } }
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/PlainHttpConnection.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/PlainHttpConnection.java Wed Dec 13 10:25:38 2017 -0800 @@ -143,7 +143,9 @@ this.chan = SocketChannel.open(); chan.configureBlocking(false); int bufsize = client.getReceiveBufferSize(); - chan.setOption(StandardSocketOptions.SO_RCVBUF, bufsize); + if (!trySetReceiveBufferSize(bufsize)) { + trySetReceiveBufferSize(256*1024); + } chan.setOption(StandardSocketOptions.TCP_NODELAY, true); // wrap the connected channel in a Tube for async reading and writing tube = new SocketTube(client(), chan, Utils::getBuffer); @@ -152,6 +154,18 @@ } } + private boolean trySetReceiveBufferSize(int bufsize) { + try { + chan.setOption(StandardSocketOptions.SO_RCVBUF, bufsize); + return true; + } catch(IOException x) { + debug.log(Level.DEBUG, + "Failed to set receive buffer size to %d on %s", + bufsize, chan); + } + return false; + } + @Override HttpPublisher publisher() { return writePublisher; }
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/WindowUpdateSender.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/WindowUpdateSender.java Wed Dec 13 10:25:38 2017 -0800 @@ -59,6 +59,8 @@ // or // - remaining window size reached max frame size. limit = Math.min(v0, v1); + debug.log(Level.DEBUG, "maxFrameSize=%d, initWindowSize=%d, limit=%d", + maxFrameSize, initWindowSize, limit); } abstract int getStreamId();
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/internal/frame/SettingsFrame.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/internal/frame/SettingsFrame.java Wed Dec 13 10:25:38 2017 -0800 @@ -100,6 +100,11 @@ this(0); } + public SettingsFrame(SettingsFrame other) { + super(0, other.flags); + parameters = Arrays.copyOf(other.parameters, MAX_PARAM); + } + @Override public int type() { return TYPE;
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java Wed Dec 13 10:25:38 2017 -0800 @@ -117,8 +117,10 @@ SourceToHTMLConverter.convertRoot(configuration, docEnv, DocPaths.SOURCE_OUTPUT); } - - if (configuration.topFile.isEmpty()) { + // Modules with no documented classes may be specified on the + // command line to specify a service provider, allow these. + if (configuration.getSpecifiedModuleElements().isEmpty() && + configuration.topFile.isEmpty()) { messages.error("doclet.No_Non_Deprecated_Classes_To_Document"); return; }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AbstractDoclet.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/AbstractDoclet.java Wed Dec 13 10:25:38 2017 -0800 @@ -193,7 +193,11 @@ * @throws DocletException if there is a problem while generating the documentation */ private void startGeneration(DocletEnvironment docEnv) throws DocletException { - if (configuration.getIncludedTypeElements().isEmpty()) { + + // Modules with no documented classes may be specified on the + // command line to specify a service provider, allow these. + if (configuration.getSpecifiedModuleElements().isEmpty() && + configuration.getIncludedTypeElements().isEmpty()) { messages.error("doclet.No_Public_Classes_To_Document"); return; }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java Wed Dec 13 10:25:38 2017 -0800 @@ -489,6 +489,10 @@ continue; } + // Skip static methods in interfaces they are not inherited + if (utils.isInterface(inheritedClass) && utils.isStatic(inheritedMember)) + continue; + // If applicable, filter those overridden methods that // should not be documented in the summary/detail sections, // and instead document them in the footnote. Care must be taken @@ -496,9 +500,8 @@ // but comments for these are synthesized on the output. ExecutableElement inheritedMethod = (ExecutableElement)inheritedMember; if (enclosedSuperMethods.stream() - .anyMatch(e -> utils.executableMembersEqual(inheritedMethod, e) - && (!utils.isSimpleOverride(e) - || visibleMemberMap.getPropertyElement(e) != null))) { + .anyMatch(e -> utils.executableMembersEqual(inheritedMethod, e) && + (!utils.isSimpleOverride(e) || visibleMemberMap.getPropertyElement(e) != null))) { inheritedMembers.add(inheritedMember); } }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Graph.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Graph.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,18 +25,14 @@ package com.sun.tools.jdeps; import java.io.PrintWriter; -import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleFinder; -import java.lang.module.ModuleReference; +import java.util.ArrayDeque; import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.Map; import java.util.Set; import java.util.function.Consumer; -import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -161,7 +157,7 @@ * Returns all nodes reachable from the given set of roots. */ public Set<T> dfs(Set<T> roots) { - Deque<T> deque = new LinkedList<>(roots); + Deque<T> deque = new ArrayDeque<>(roots); Set<T> visited = new HashSet<>(); while (!deque.isEmpty()) { T u = deque.pop(); @@ -197,7 +193,7 @@ if (includeAdjacent && isAdjacent(u, v)) { return true; } - Deque<T> stack = new LinkedList<>(); + Deque<T> stack = new ArrayDeque<>(); Set<T> visited = new HashSet<>(); stack.push(u); while (!stack.isEmpty()) { @@ -292,12 +288,10 @@ * Topological sort */ static class TopoSorter<T> { - final Deque<T> result = new LinkedList<>(); - final Deque<T> nodes; + final Deque<T> result = new ArrayDeque<>(); final Graph<T> graph; TopoSorter(Graph<T> graph) { this.graph = graph; - this.nodes = new LinkedList<>(graph.nodes); sort(); } @@ -310,17 +304,16 @@ } private void sort() { - Deque<T> visited = new LinkedList<>(); - Deque<T> done = new LinkedList<>(); - T node; - while ((node = nodes.poll()) != null) { + Set<T> visited = new HashSet<>(); + Set<T> done = new HashSet<>(); + for (T node : graph.nodes()) { if (!visited.contains(node)) { visit(node, visited, done); } } } - private void visit(T node, Deque<T> visited, Deque<T> done) { + private void visit(T node, Set<T> visited, Set<T> done) { if (visited.contains(node)) { if (!done.contains(node)) { throw new IllegalArgumentException("Cyclic detected: " + @@ -330,7 +323,7 @@ } visited.add(node); graph.edges().get(node).stream() - .forEach(x -> visit(x, visited, done)); + .forEach(x -> visit(x, visited, done)); done.add(node); result.addLast(node); }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java Wed Dec 13 10:25:38 2017 -0800 @@ -38,8 +38,6 @@ import java.io.UncheckedIOException; import java.lang.module.Configuration; import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleDescriptor.Exports; -import java.lang.module.ModuleDescriptor.Opens; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; @@ -71,6 +69,7 @@ public static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; public static final String ALL_DEFAULT = "ALL-DEFAULT"; public static final String ALL_SYSTEM = "ALL-SYSTEM"; + public static final String MODULE_INFO = "module-info.class"; private final SystemModuleFinder system; @@ -91,8 +90,7 @@ Set<String> roots, List<Path> classpaths, List<Archive> initialArchives, - boolean allDefaultModules, - boolean allSystemModules, + Set<String> tokens, Runtime.Version version) throws IOException { @@ -104,16 +102,13 @@ // build root set for resolution Set<String> mods = new HashSet<>(roots); - - // add all system modules to the root set for unnamed module or set explicitly - boolean unnamed = !initialArchives.isEmpty() || !classpaths.isEmpty(); - if (allSystemModules || (unnamed && !allDefaultModules)) { + if (tokens.contains(ALL_SYSTEM)) { systemModulePath.findAll().stream() .map(mref -> mref.descriptor().name()) .forEach(mods::add); } - if (allDefaultModules) { + if (tokens.contains(ALL_DEFAULT)) { mods.addAll(systemModulePath.defaultSystemRoots()); } @@ -200,10 +195,10 @@ return m!= null ? Optional.of(m.descriptor()) : Optional.empty(); } - boolean isValidToken(String name) { + public static boolean isToken(String name) { return ALL_MODULE_PATH.equals(name) || - ALL_DEFAULT.equals(name) || - ALL_SYSTEM.equals(name); + ALL_DEFAULT.equals(name) || + ALL_SYSTEM.equals(name); } /** @@ -482,13 +477,10 @@ final List<Archive> initialArchives = new ArrayList<>(); final List<Path> paths = new ArrayList<>(); final List<Path> classPaths = new ArrayList<>(); + final Set<String> tokens = new HashSet<>(); ModuleFinder upgradeModulePath; ModuleFinder appModulePath; - boolean addAllApplicationModules; - boolean addAllDefaultModules; - boolean addAllSystemModules; - boolean allModules; Runtime.Version version; public Builder() { @@ -513,34 +505,15 @@ public Builder addmods(Set<String> addmods) { for (String mn : addmods) { - switch (mn) { - case ALL_MODULE_PATH: - this.addAllApplicationModules = true; - break; - case ALL_DEFAULT: - this.addAllDefaultModules = true; - break; - case ALL_SYSTEM: - this.addAllSystemModules = true; - break; - default: - this.rootModules.add(mn); + if (isToken(mn)) { + tokens.add(mn); + } else { + rootModules.add(mn); } } return this; } - /* - * This method is for --check option to find all target modules specified - * in qualified exports. - * - * Include all system modules and modules found on modulepath - */ - public Builder allModules() { - this.allModules = true; - return this; - } - public Builder multiRelease(Runtime.Version version) { this.version = version; return this; @@ -579,7 +552,9 @@ .forEach(rootModules::add); } - if ((addAllApplicationModules || allModules) && appModulePath != null) { + // add all modules to the root set for unnamed module or set explicitly + boolean unnamed = !initialArchives.isEmpty() || !classPaths.isEmpty(); + if ((unnamed || tokens.contains(ALL_MODULE_PATH)) && appModulePath != null) { appModulePath.findAll().stream() .map(mref -> mref.descriptor().name()) .forEach(rootModules::add); @@ -587,7 +562,7 @@ // no archive is specified for analysis // add all system modules as root if --add-modules ALL-SYSTEM is specified - if (addAllSystemModules && rootModules.isEmpty() && + if (tokens.contains(ALL_SYSTEM) && rootModules.isEmpty() && initialArchives.isEmpty() && classPaths.isEmpty()) { systemModulePath.findAll() .stream() @@ -595,13 +570,16 @@ .forEach(rootModules::add); } + if (unnamed && !tokens.contains(ALL_DEFAULT)) { + tokens.add(ALL_SYSTEM); + } + return new JdepsConfiguration(systemModulePath, finder, rootModules, classPaths, initialArchives, - addAllDefaultModules, - allModules, + tokens, version); }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -540,7 +540,7 @@ } boolean run() throws IOException { - try (JdepsConfiguration config = buildConfig(command.allModules())) { + try (JdepsConfiguration config = buildConfig()) { if (!options.nowarning) { // detect split packages config.splitPackages().entrySet() @@ -553,7 +553,7 @@ // check if any module specified in --add-modules, --require, and -m is missing options.addmods.stream() - .filter(mn -> !config.isValidToken(mn)) + .filter(mn -> !JdepsConfiguration.isToken(mn)) .forEach(mn -> config.findModule(mn).orElseThrow(() -> new UncheckedBadArgs(new BadArgs("err.module.not.found", mn)))); @@ -561,18 +561,14 @@ } } - private JdepsConfiguration buildConfig(boolean allModules) throws IOException { + private JdepsConfiguration buildConfig() throws IOException { JdepsConfiguration.Builder builder = new JdepsConfiguration.Builder(options.systemModulePath); builder.upgradeModulePath(options.upgradeModulePath) .appModulePath(options.modulePath) - .addmods(options.addmods); - - if (allModules) { - // check all system modules in the image - builder.allModules(); - } + .addmods(options.addmods) + .addmods(command.addModules()); if (options.classpath != null) builder.addClassPath(options.classpath); @@ -655,8 +651,8 @@ * only. The method should be overridden when this command should * analyze all modules instead. */ - boolean allModules() { - return false; + Set<String> addModules() { + return Set.of(); } @Override @@ -871,8 +867,8 @@ * analyzed to find all modules that depend on the modules specified in the * --require option directly and indirectly */ - public boolean allModules() { - return options.requires.size() > 0; + Set<String> addModules() { + return options.requires.size() > 0 ? Set.of("ALL-SYSTEM") : Set.of(); } } @@ -975,8 +971,8 @@ /* * Returns true to analyze all modules */ - public boolean allModules() { - return true; + Set<String> addModules() { + return Set.of("ALL-SYSTEM", "ALL-MODULE-PATH"); } }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java Wed Dec 13 10:25:38 2017 -0800 @@ -32,7 +32,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import java.util.Optional; import java.util.Set; /** @@ -138,7 +137,7 @@ // for debugging public static void main(String[] args) throws IOException { // initialize Profiles - new JdepsConfiguration.Builder().allModules().build(); + new JdepsConfiguration.Builder().addmods(Set.of("ALL-SYSTEM")).build(); // find platform modules if (Profile.getProfileCount() == 0) {
--- a/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryConnection.c Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.jdi/share/native/libdt_shmem/SharedMemoryConnection.c Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,7 +111,7 @@ jint tmpInt; total_length = str->type.cmd.len; - data_length = total_length - 11; + data_length = total_length - JDWP_HEADER_SIZE; /* total packet length is header + data */ array = (*env)->NewByteArray(env, total_length); @@ -142,7 +142,7 @@ /* finally the data */ if (data_length > 0) { - (*env)->SetByteArrayRegion(env, array, 11, + (*env)->SetByteArrayRegion(env, array, JDWP_HEADER_SIZE, data_length, str->type.cmd.data); if ((*env)->ExceptionOccurred(env)) { return NULL; @@ -168,7 +168,7 @@ { jsize total_length, data_length; jbyte *data; - unsigned char pktHeader[11]; /* sizeof length + id + flags + cmdSet + cmd */ + unsigned char pktHeader[JDWP_HEADER_SIZE]; /* * Get the packet header
--- a/src/jdk.jdi/share/native/libdt_shmem/shmemBack.c Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.jdi/share/native/libdt_shmem/shmemBack.c Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -270,7 +270,7 @@ if (packet == NULL) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "packet is null"); } - if (packet->type.cmd.len < 11) { + if (packet->type.cmd.len < JDWP_HEADER_SIZE) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "invalid length"); } if (connection == NULL) {
--- a/src/jdk.jdi/share/native/libdt_shmem/shmemBase.c Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.jdi/share/native/libdt_shmem/shmemBase.c Wed Dec 13 10:25:38 2017 -0800 @@ -1049,7 +1049,7 @@ CHECK_ERROR(sendBytes(connection, &packet->type.cmd.cmd, sizeof(jbyte))); } - data_length = packet->type.cmd.len - 11; + data_length = packet->type.cmd.len - JDWP_HEADER_SIZE; SHMEM_GUARANTEE(data_length >= 0); CHECK_ERROR(sendBytes(connection, &data_length, sizeof(jint))); @@ -1125,10 +1125,10 @@ if (data_length < 0) { return SYS_ERR; } else if (data_length == 0) { - packet->type.cmd.len = 11; + packet->type.cmd.len = JDWP_HEADER_SIZE; packet->type.cmd.data = NULL; } else { - packet->type.cmd.len = data_length + 11; + packet->type.cmd.len = data_length + JDWP_HEADER_SIZE; packet->type.cmd.data = (*callback->alloc)(data_length); if (packet->type.cmd.data == NULL) { return SYS_ERR;
--- a/src/jdk.jdwp.agent/share/native/include/jdwpTransport.h Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.jdwp.agent/share/native/include/jdwpTransport.h Wed Dec 13 10:25:38 2017 -0800 @@ -96,6 +96,8 @@ * See: http://java.sun.com/j2se/1.5/docs/guide/jpda/jdwp-spec.html */ +#define JDWP_HEADER_SIZE 11 + enum { /* * If additional flags are added that apply to jdwpCmdPacket,
--- a/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c Wed Dec 13 10:25:38 2017 -0800 @@ -70,7 +70,6 @@ RETURN_IO_ERROR("recv error"); \ } -#define HEADER_SIZE 11 #define MAX_DATA_SIZE 1000 static jint recv_fully(int, char *, int); @@ -790,7 +789,7 @@ /* * room for header and up to MAX_DATA_SIZE data bytes */ - char header[HEADER_SIZE + MAX_DATA_SIZE]; + char header[JDWP_HEADER_SIZE + MAX_DATA_SIZE]; jbyte *data; /* packet can't be null */ @@ -799,7 +798,7 @@ } len = packet->type.cmd.len; /* includes header */ - data_len = len - HEADER_SIZE; + data_len = len - JDWP_HEADER_SIZE; /* bad packet */ if (data_len < 0) { @@ -825,15 +824,15 @@ data = packet->type.cmd.data; /* Do one send for short packets, two for longer ones */ if (data_len <= MAX_DATA_SIZE) { - memcpy(header + HEADER_SIZE, data, data_len); - if (send_fully(socketFD, (char *)&header, HEADER_SIZE + data_len) != - HEADER_SIZE + data_len) { + memcpy(header + JDWP_HEADER_SIZE, data, data_len); + if (send_fully(socketFD, (char *)&header, JDWP_HEADER_SIZE + data_len) != + JDWP_HEADER_SIZE + data_len) { RETURN_IO_ERROR("send failed"); } } else { - memcpy(header + HEADER_SIZE, data, MAX_DATA_SIZE); - if (send_fully(socketFD, (char *)&header, HEADER_SIZE + MAX_DATA_SIZE) != - HEADER_SIZE + MAX_DATA_SIZE) { + memcpy(header + JDWP_HEADER_SIZE, data, MAX_DATA_SIZE); + if (send_fully(socketFD, (char *)&header, JDWP_HEADER_SIZE + MAX_DATA_SIZE) != + JDWP_HEADER_SIZE + MAX_DATA_SIZE) { RETURN_IO_ERROR("send failed"); } /* Send the remaining data bytes right out of the data area. */
--- a/src/jdk.jdwp.agent/share/native/libjdwp/inStream.c Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.jdwp.agent/share/native/libjdwp/inStream.c Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ { stream->packet = packet; stream->error = JDWP_ERROR(NONE); - stream->left = packet.type.cmd.len; + stream->left = packet.type.cmd.len - JDWP_HEADER_SIZE; stream->current = packet.type.cmd.data; stream->refs = bagCreateBag(sizeof(jobject), INITIAL_REF_ALLOC); if (stream->refs == NULL) { @@ -411,12 +411,6 @@ return string; } -jboolean -inStream_endOfInput(PacketInputStream *stream) -{ - return (stream->left > 0); -} - jdwpError inStream_error(PacketInputStream *stream) { @@ -424,7 +418,8 @@ } void -inStream_clearError(PacketInputStream *stream) { +inStream_clearError(PacketInputStream *stream) +{ stream->error = JDWP_ERROR(NONE); }
--- a/src/jdk.jdwp.agent/share/native/libjdwp/inStream.h Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.jdwp.agent/share/native/libjdwp/inStream.h Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,6 @@ jdwpError inStream_skipBytes(PacketInputStream *stream, jint count); -jboolean inStream_endOfInput(PacketInputStream *stream); jdwpError inStream_error(PacketInputStream *stream); void inStream_clearError(PacketInputStream *stream); void inStream_destroy(PacketInputStream *stream);
--- a/src/jdk.jdwp.agent/share/native/libjdwp/outStream.c Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.jdwp.agent/share/native/libjdwp/outStream.c Wed Dec 13 10:25:38 2017 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -418,7 +418,7 @@ * packet. */ if (stream->firstSegment.next == NULL) { - stream->packet.type.cmd.len = 11 + stream->firstSegment.length; + stream->packet.type.cmd.len = JDWP_HEADER_SIZE + stream->firstSegment.length; stream->packet.type.cmd.data = stream->firstSegment.data; rc = transport_sendPacket(&stream->packet); return rc; @@ -447,7 +447,7 @@ segment = segment->next; } - stream->packet.type.cmd.len = 11 + len; + stream->packet.type.cmd.len = JDWP_HEADER_SIZE + len; stream->packet.type.cmd.data = data; rc = transport_sendPacket(&stream->packet); stream->packet.type.cmd.data = NULL;
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java Wed Dec 13 13:27:45 2017 +0530 +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java Wed Dec 13 10:25:38 2017 -0800 @@ -43,6 +43,7 @@ import java.nio.charset.Charset; import java.nio.file.FileSystems; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.text.MessageFormat; @@ -387,7 +388,7 @@ private Collection<String> validPaths(Collection<String> vals, String context, boolean isModulePath) { Stream<String> result = vals.stream() .map(s -> Arrays.stream(s.split(File.pathSeparator)) - .map(sp -> toPathResolvingUserHome(sp)) + .flatMap(sp -> toPathImpl(sp, context)) .filter(p -> checkValidPathEntry(p, context, isModulePath)) .map(p -> p.toString()) .collect(Collectors.joining(File.pathSeparator))); @@ -427,6 +428,16 @@ return false; } + private Stream<Path> toPathImpl(String path, String context) { + try { + return Stream.of(toPathResolvingUserHome(path)); + } catch (InvalidPathException ex) { + msg("jshell.err.file.not.found", context, path); + failed = true; + return Stream.empty(); + } + } + Options parse(OptionSet options) { addOptions(OptionKind.CLASS_PATH, validPaths(options.valuesOf(argClassPath), "--class-path", false));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.localedata/share/classes/sun/util/cldr/resources/common/bcp47/timezone.xml Wed Dec 13 10:25:38 2017 -0800 @@ -0,0 +1,470 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE ldmlBCP47 SYSTEM "../../common/dtd/ldmlBCP47.dtd"> +<!-- +Copyright © 1991-2013 Unicode, Inc. +CLDR data files are interpreted according to the LDML specification (http://unicode.org/reports/tr35/) +For terms of use, see http://www.unicode.org/copyright.html +--> + +<ldmlBCP47> + <version number="$Revision: 12146 $"/> + <keyword> + <key name="tz" description="Time zone key" alias="timezone"> + <type name="adalv" description="Andorra" alias="Europe/Andorra"/> + <type name="aedxb" description="Dubai, United Arab Emirates" alias="Asia/Dubai"/> + <type name="afkbl" description="Kabul, Afghanistan" alias="Asia/Kabul"/> + <type name="aganu" description="Antigua" alias="America/Antigua"/> + <type name="aiaxa" description="Anguilla" alias="America/Anguilla"/> + <type name="altia" description="Tirane, Albania" alias="Europe/Tirane"/> + <type name="amevn" description="Yerevan, Armenia" alias="Asia/Yerevan"/> + <type name="ancur" description="Curaçao" alias="America/Curacao"/> + <type name="aolad" description="Luanda, Angola" alias="Africa/Luanda"/> + <type name="aqams" description="Amundsen-Scott Station, South Pole" deprecated="true" preferred="nzakl"/> + <type name="aqcas" description="Casey Station, Bailey Peninsula" alias="Antarctica/Casey"/> + <type name="aqdav" description="Davis Station, Vestfold Hills" alias="Antarctica/Davis"/> + <type name="aqddu" description="Dumont d'Urville Station, Terre Adélie" alias="Antarctica/DumontDUrville"/> + <type name="aqmaw" description="Mawson Station, Holme Bay" alias="Antarctica/Mawson"/> + <type name="aqmcm" description="McMurdo Station, Ross Island" alias="Antarctica/McMurdo"/> + <type name="aqplm" description="Palmer Station, Anvers Island" alias="Antarctica/Palmer"/> + <type name="aqrot" description="Rothera Station, Adelaide Island" alias="Antarctica/Rothera"/> + <type name="aqsyw" description="Syowa Station, East Ongul Island" alias="Antarctica/Syowa"/> + <type name="aqtrl" description="Troll Station, Queen Maud Land" alias="Antarctica/Troll" since="26"/> + <type name="aqvos" description="Vostok Station, Lake Vostok" alias="Antarctica/Vostok"/> + <type name="arbue" description="Buenos Aires, Argentina" alias="America/Buenos_Aires America/Argentina/Buenos_Aires"/> + <type name="arcor" description="Córdoba, Argentina" alias="America/Cordoba America/Argentina/Cordoba America/Rosario"/> + <type name="arctc" description="Catamarca, Argentina" alias="America/Catamarca America/Argentina/Catamarca America/Argentina/ComodRivadavia"/> + <type name="arirj" description="La Rioja, Argentina" alias="America/Argentina/La_Rioja"/> + <type name="arjuj" description="Jujuy, Argentina" alias="America/Jujuy America/Argentina/Jujuy"/> + <type name="arluq" description="San Luis, Argentina" alias="America/Argentina/San_Luis"/> + <type name="armdz" description="Mendoza, Argentina" alias="America/Mendoza America/Argentina/Mendoza"/> + <type name="arrgl" description="Río Gallegos, Argentina" alias="America/Argentina/Rio_Gallegos"/> + <type name="arsla" description="Salta, Argentina" alias="America/Argentina/Salta"/> + <type name="artuc" description="Tucumán, Argentina" alias="America/Argentina/Tucuman"/> + <type name="aruaq" description="San Juan, Argentina" alias="America/Argentina/San_Juan"/> + <type name="arush" description="Ushuaia, Argentina" alias="America/Argentina/Ushuaia"/> + <type name="asppg" description="Pago Pago, American Samoa" alias="Pacific/Pago_Pago Pacific/Samoa US/Samoa"/> + <type name="atvie" description="Vienna, Austria" alias="Europe/Vienna"/> + <type name="auadl" description="Adelaide, Australia" alias="Australia/Adelaide Australia/South"/> + <type name="aubhq" description="Broken Hill, Australia" alias="Australia/Broken_Hill Australia/Yancowinna"/> + <type name="aubne" description="Brisbane, Australia" alias="Australia/Brisbane Australia/Queensland"/> + <type name="audrw" description="Darwin, Australia" alias="Australia/Darwin Australia/North"/> + <type name="aueuc" description="Eucla, Australia" alias="Australia/Eucla"/> + <type name="auhba" description="Hobart, Australia" alias="Australia/Hobart Australia/Tasmania"/> + <type name="aukns" description="Currie, Australia" alias="Australia/Currie"/> + <type name="auldc" description="Lindeman Island, Australia" alias="Australia/Lindeman"/> + <type name="auldh" description="Lord Howe Island, Australia" alias="Australia/Lord_Howe Australia/LHI"/> + <type name="aumel" description="Melbourne, Australia" alias="Australia/Melbourne Australia/Victoria"/> + <type name="aumqi" description="Macquarie Island Station, Macquarie Island" alias="Antarctica/Macquarie" since="1.8.1"/> + <type name="auper" description="Perth, Australia" alias="Australia/Perth Australia/West"/> + <type name="ausyd" description="Sydney, Australia" alias="Australia/Sydney Australia/ACT Australia/Canberra Australia/NSW"/> + <type name="awaua" description="Aruba" alias="America/Aruba"/> + <type name="azbak" description="Baku, Azerbaijan" alias="Asia/Baku"/> + <type name="basjj" description="Sarajevo, Bosnia and Herzegovina" alia