Mercurial > hg > icedtea9-forest > jdk
changeset 5734:4419c8f0b2f2
6380549: (rb) ResourceBundle.Control global binding support
Reviewed-by: naoto
line wrap: on
line diff
--- a/make/java/java/FILES_java.gmk Mon Jun 18 11:19:48 2012 +0100 +++ b/make/java/java/FILES_java.gmk Tue Jun 19 16:21:17 2012 +0900 @@ -372,6 +372,7 @@ java/util/spi/CurrencyNameProvider.java \ java/util/spi/LocaleNameProvider.java \ java/util/spi/LocaleServiceProvider.java \ + java/util/spi/ResourceBundleControlProvider.java \ java/util/spi/TimeZoneNameProvider.java \ java/io/Closeable.java \ java/io/Flushable.java \
--- a/src/share/classes/java/util/ResourceBundle.java Mon Jun 18 11:19:48 2012 +0100 +++ b/src/share/classes/java/util/ResourceBundle.java Tue Jun 19 16:21:17 2012 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2012, 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 @@ -55,6 +55,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.jar.JarEntry; +import java.util.spi.ResourceBundleControlProvider; import sun.util.locale.BaseLocale; import sun.util.locale.LocaleObjectCache; @@ -192,6 +193,17 @@ * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle} * factory method for details. * + * <p><a name="modify_default_behavior">For the {@code getBundle} factory + * methods that take no {@link Control} instance, their <a + * href="#default_behavior"> default behavior</a> of resource bundle loading + * can be modified with <em>installed</em> {@link + * ResourceBundleControlProvider} implementations. Any installed providers are + * detected at the {@code ResourceBundle} class loading time. If any of the + * providers provides a {@link Control} for the given base name, that {@link + * Control} will be used instead of the default {@link Control}. If there is + * more than one service provider installed for supporting the same base name, + * the first one returned from {@link ServiceLoader} will be used. + * * <h4>Cache Management</h4> * * Resource bundle instances created by the <code>getBundle</code> factory @@ -294,8 +306,7 @@ /** * Queue for reference objects referring to class loaders or bundles. */ - private static final ReferenceQueue<Object> referenceQueue = - new ReferenceQueue<>(); + private static final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>(); /** * The parent bundle of this bundle. @@ -330,6 +341,21 @@ */ private volatile Set<String> keySet; + private static final List<ResourceBundleControlProvider> providers; + + static { + List<ResourceBundleControlProvider> list = null; + ServiceLoader<ResourceBundleControlProvider> serviceLoaders + = ServiceLoader.loadInstalled(ResourceBundleControlProvider.class); + for (ResourceBundleControlProvider provider : serviceLoaders) { + if (list == null) { + list = new ArrayList<>(); + } + list.add(provider); + } + providers = list; + } + /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) @@ -725,7 +751,7 @@ return getBundleImpl(baseName, Locale.getDefault(), /* must determine loader here, else we break stack invariant */ getLoader(), - Control.INSTANCE); + getDefaultControl(baseName)); } /** @@ -797,7 +823,7 @@ return getBundleImpl(baseName, locale, /* must determine loader here, else we break stack invariant */ getLoader(), - Control.INSTANCE); + getDefaultControl(baseName)); } /** @@ -849,9 +875,15 @@ * Gets a resource bundle using the specified base name, locale, and class * loader. * - * <p><a name="default_behavior"/>This method behaves the same as calling + * <p>This method behaves the same as calling * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a - * default instance of {@link Control}. The following describes this behavior. + * default instance of {@link Control} unless another {@link Control} is + * provided with the {@link ResourceBundleControlProvider} SPI. Refer to the + * description of <a href="#modify_default_behavior">modifying the default + * behavior</a>. + * + * <p><a name="default_behavior"/>The following describes the default + * behavior. * * <p><code>getBundle</code> uses the base name, the specified locale, and * the default locale (obtained from {@link java.util.Locale#getDefault() @@ -1026,7 +1058,7 @@ if (loader == null) { throw new NullPointerException(); } - return getBundleImpl(baseName, locale, loader, Control.INSTANCE); + return getBundleImpl(baseName, locale, loader, getDefaultControl(baseName)); } /** @@ -1247,6 +1279,18 @@ return getBundleImpl(baseName, targetLocale, loader, control); } + private static Control getDefaultControl(String baseName) { + if (providers != null) { + for (ResourceBundleControlProvider provider : providers) { + Control control = provider.getControl(baseName); + if (control != null) { + return control; + } + } + } + return Control.INSTANCE; + } + private static ResourceBundle getBundleImpl(String baseName, Locale locale, ClassLoader loader, Control control) { if (locale == null || control == null) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/util/spi/ResourceBundleControlProvider.java Tue Jun 19 16:21:17 2012 +0900 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, 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.util.spi; + +import java.util.ResourceBundle; + +/** + * An interface for service providers that provide implementations of {@link + * java.util.ResourceBundle.Control}. The <a + * href="../ResourceBundle.html#default_behavior">default resource bundle loading + * behavior</a> of the {@code ResourceBundle.getBundle} factory methods that take + * no {@link java.util.ResourceBundle.Control} instance can be modified with {@code + * ResourceBundleControlProvider} implementations. + * + * <p>Provider implementations must be packaged using the <a + * href="../../../../technotes/guides/extensions/index.html">Java Extension + * Mechanism</a> as installed extensions. Refer to {@link java.util.ServiceLoader} + * for the extension packaging. Any installed {@code + * ResourceBundleControlProvider} implementations are loaded using {@link + * java.util.ServiceLoader} at the {@code ResourceBundle} class loading time. + * + * @author Masayoshi Okutsu + * @since 1.8 + * @see ResourceBundle#getBundle(String, java.util.Locale, ClassLoader, ResourceBundle.Control) + * ResourceBundle.getBundle + * @see java.util.ServiceLoader#loadInstalled(Class) + */ +public interface ResourceBundleControlProvider { + /** + * Returns a {@code ResourceBundle.Control} instance that is used + * to handle resource bundle loading for the given {@code + * baseName}. This method must return {@code null} if the given + * {@code baseName} isn't handled by this provider. + * + * @param baseName the base name of the resource bundle + * @return a {@code ResourceBundle.Control} instance, + * or {@code null} if the given {@code baseName} is not + * applicable to this provider. + * @throws NullPointerException if {@code baseName} is {@code null} + */ + public ResourceBundle.Control getControl(String baseName); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.java Tue Jun 19 16:21:17 2012 +0900 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012, 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. + * + * 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. + */ +/* + * @test + * @bug 6959653 + * @summary Test ResourceBundle.Control provided using SPI. + * @build UserDefaultControlTest + * @run shell UserDefaultControlTest.sh + */ + +import java.io.*; +import java.net.*; +import java.util.*; + +public class UserDefaultControlTest { + public static void main(String[] args) { + ResourceBundle rb = ResourceBundle.getBundle("com.foo.XmlRB", Locale.ROOT); + String type = rb.getString("type"); + if (!type.equals("XML")) { + throw new RuntimeException("Root Locale: type: got " + type + + ", expected XML (ASCII)"); + } + + rb = ResourceBundle.getBundle("com.foo.XmlRB", Locale.JAPAN); + type = rb.getString("type"); + // Expect fullwidth "XML" + if (!type.equals("\uff38\uff2d\uff2c")) { + throw new RuntimeException("Locale.JAPAN: type: got " + type + + ", expected \uff38\uff2d\uff2c (fullwidth XML)"); + } + + try { + rb = ResourceBundle.getBundle("com.bar.XmlRB", Locale.JAPAN); + throw new RuntimeException("com.bar.XmlRB test failed."); + } catch (MissingResourceException e) { + // OK + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.sh Tue Jun 19 16:21:17 2012 +0900 @@ -0,0 +1,24 @@ +# +# Copyright (c) 2012, 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. +# +# 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. +# + +${TESTJAVA}/bin/java -Djava.ext.dirs=${TESTSRC} -cp ${TESTCLASSES} UserDefaultControlTest \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/spi/ResourceBundleControlProvider/providersrc/Makefile Tue Jun 19 16:21:17 2012 +0900 @@ -0,0 +1,63 @@ +# +# Copyright (c) 2012, 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. +# + +# +# Makefile for building a ResourceBundleControlProvider jar file for testing. +# +# Usage: make JDK_HOME=... all install +# + +DESTDIR = .. +TMPDIR = tmp +SERVICESDIR = $(TMPDIR)/META-INF/services +TARGETJAR = rbcontrolprovider.jar +BINDIR = $(JDK_HOME)/bin + + +all: $(TARGETJAR) + +install: all + cp $(TARGETJAR) $(DESTDIR) + +SERVICES = java.util.spi.ResourceBundleControlProvider + +FILES_JAVA = UserControlProvider.java \ + UserXMLControl.java + +RESOURCE_FILES = XmlRB.xml \ + XmlRB_ja.xml + +$(TARGETJAR): $(SERVICES) $(FILES_JAVA) $(RESOURCE_FILES) + rm -rf $(TMPDIR) $@ + mkdir -p $(SERVICESDIR) + $(BINDIR)/javac -d $(TMPDIR) $(FILES_JAVA) + cp $(SERVICES) $(SERVICESDIR) + cp $(RESOURCE_FILES) $(TMPDIR)/com/foo + $(BINDIR)/jar cvf $@ -C $(TMPDIR) . + +clean: + rm -rf $(TMPDIR) $(TARGETJAR) + +.PHONY: all install clean
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/spi/ResourceBundleControlProvider/providersrc/UserControlProvider.java Tue Jun 19 16:21:17 2012 +0900 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, 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 com.foo; + +import java.util.ResourceBundle; +import java.util.spi.ResourceBundleControlProvider; + +public class UserControlProvider implements ResourceBundleControlProvider { + static final ResourceBundle.Control XMLCONTROL = new UserXMLControl(); + + public ResourceBundle.Control getControl(String baseName) { + System.out.println(getClass().getName()+".getControl called for " + baseName); + + // Throws a NPE if baseName is null. + if (baseName.startsWith("com.foo.Xml")) { + System.out.println("\treturns " + XMLCONTROL); + return XMLCONTROL; + } + System.out.println("\treturns null"); + return null; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/spi/ResourceBundleControlProvider/providersrc/UserXMLControl.java Tue Jun 19 16:21:17 2012 +0900 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, 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. + * + * 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 com.foo; + +import java.io.*; +import java.net.*; +import java.util.*; +import static java.util.ResourceBundle.Control.*; + +public class UserXMLControl extends ResourceBundle.Control { + @Override + public List<String> getFormats(String baseName) { + if (baseName == null) { + throw new NullPointerException(); + } + return Arrays.asList("xml"); + } + + @Override + public ResourceBundle newBundle(String baseName, Locale locale, + String format, + ClassLoader loader, + boolean reload) + throws IllegalAccessException, + InstantiationException, IOException { + if (baseName == null || locale == null + || format == null || loader == null) { + throw new NullPointerException(); + } + ResourceBundle bundle = null; + if (format.equals("xml")) { + String bundleName = toBundleName(baseName, locale); + String resourceName = toResourceName(bundleName, format); + URL url = loader.getResource(resourceName); + if (url != null) { + URLConnection connection = url.openConnection(); + if (connection != null) { + if (reload) { + // disable caches if reloading + connection.setUseCaches(false); + } + try (InputStream stream = connection.getInputStream()) { + if (stream != null) { + BufferedInputStream bis = new BufferedInputStream(stream); + bundle = new XMLResourceBundle(bis); + } + } + } + } + } + return bundle; + } + + private static class XMLResourceBundle extends ResourceBundle { + private Properties props; + + XMLResourceBundle(InputStream stream) throws IOException { + props = new Properties(); + props.loadFromXML(stream); + } + + protected Object handleGetObject(String key) { + if (key == null) { + throw new NullPointerException(); + } + return props.get(key); + } + + public Enumeration<String> getKeys() { + // Not implemented + return null; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/spi/ResourceBundleControlProvider/providersrc/XmlRB.xml Tue Jun 19 16:21:17 2012 +0900 @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2012, 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. +--> +<!----> + +<!-- DTD for properties --> +<!DOCTYPE properties [ +<!ELEMENT properties ( comment?, entry* ) > +<!ATTLIST properties version CDATA #FIXED "1.0"> +<!ELEMENT comment (#PCDATA) > +<!ELEMENT entry (#PCDATA) > +<!ATTLIST entry key CDATA #REQUIRED> +]> + +<properties> + <comment>Test data for UserDefaultControlTest.java</comment> + <entry key="type">XML</entry> +</properties>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/spi/ResourceBundleControlProvider/providersrc/XmlRB_ja.xml Tue Jun 19 16:21:17 2012 +0900 @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2012, 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. +--> +<!----> + +<!-- DTD for properties --> +<!DOCTYPE properties [ +<!ELEMENT properties ( comment?, entry* ) > +<!ATTLIST properties version CDATA #FIXED "1.0"> +<!ELEMENT comment (#PCDATA) > +<!ELEMENT entry (#PCDATA) > +<!ATTLIST entry key CDATA #REQUIRED> +]> + +<properties> + <comment>Test data for UserDefaultControlTest.java</comment> + <entry key="type">XML</entry> +</properties>