提交 465653bb 编写于 作者: A alanb

8000354: (props) Properties.storeToXML/loadFromXML need to allow for alternative implementations

Reviewed-by: mchung, forax
上级 e3a9fce5
......@@ -236,6 +236,7 @@ JAVA_JAVA_java = \
java/util/Observer.java \
java/util/Properties.java \
java/util/InvalidPropertiesFormatException.java \
sun/util/spi/XmlPropertiesProvider.java \
java/util/PropertyPermission.java \
java/util/PropertyResourceBundle.java \
java/util/Random.java \
......
......@@ -41,3 +41,20 @@ AUTO_FILES_JAVA_DIRS = sun/util/xml
#
include $(BUILDDIR)/common/Classes.gmk
#
# Rules for XML properties provider configuration file
#
SERVICEDIR = $(CLASSBINDIR)/META-INF/services
FILES_copy = $(SERVICEDIR)/sun.util.spi.XmlPropertiesProvider
copy-files: $(FILES_copy)
$(SERVICEDIR)/%: $(SHARE_SRC)/classes/sun/util/xml/META-INF/services/%
$(install-file)
build: copy-files
clean::
$(RM) $(FILES_copy)
......@@ -34,7 +34,10 @@ import java.io.Reader;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
import java.lang.reflect.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.util.spi.XmlPropertiesProvider;
/**
* The {@code Properties} class represents a persistent set of
......@@ -866,7 +869,7 @@ class Properties extends Hashtable<Object,Object> {
{
if (in == null)
throw new NullPointerException();
XMLUtils.load(this, in);
XmlSupport.load(this, in);
in.close();
}
......@@ -934,7 +937,7 @@ class Properties extends Hashtable<Object,Object> {
{
if (os == null)
throw new NullPointerException();
XMLUtils.save(this, os, comment, encoding);
XmlSupport.save(this, os, comment, encoding);
}
/**
......@@ -1113,59 +1116,82 @@ class Properties extends Hashtable<Object,Object> {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
};
/**
* Supporting class for loading/storing properties in XML format.
*
* <p> The {@code load} and {@code store} methods defined here delegate to a
* system-wide {@code XmlPropertiesProvider}. On first invocation of either
* method then the system-wide provider is located as follows: </p>
*
* <ol>
* <li> If the system property {@code sun.util.spi.XmlPropertiesProvider}
* is defined then it is taken to be the full-qualified name of a concrete
* provider class. The class is loaded with the system class loader as the
* initiating loader. If it cannot be loaded or instantiated using a zero
* argument constructor then an unspecified error is thrown. </li>
*
* <li> If the system property is not defined then the service-provider
* loading facility defined by the {@link ServiceLoader} class is used to
* locate a provider with the system class loader as the initiating
* loader and {@code sun.util.spi.XmlPropertiesProvider} as the service
* type. If this process fails then an unspecified error is thrown. If
* there is more than one service provider installed then it is
* not specified as to which provider will be used. </li>
*
* <li> If the provider is not found by the above means then a system
* default provider will be instantiated and used. </li>
* </ol>
*/
private static class XmlSupport {
private static class XMLUtils {
private static Method load = null;
private static Method save = null;
static {
private static XmlPropertiesProvider loadProviderFromProperty(ClassLoader cl) {
String cn = System.getProperty("sun.util.spi.XmlPropertiesProvider");
if (cn == null)
return null;
try {
// reference sun.util.xml.Utils reflectively
// to allow the Properties class be compiled in
// the absence of XML
Class<?> c = Class.forName("sun.util.xml.XMLUtils", true, null);
load = c.getMethod("load", Properties.class, InputStream.class);
save = c.getMethod("save", Properties.class, OutputStream.class,
String.class, String.class);
} catch (ClassNotFoundException cnf) {
throw new AssertionError(cnf);
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
Class<?> c = Class.forName(cn, true, cl);
return (XmlPropertiesProvider)c.newInstance();
} catch (ClassNotFoundException |
IllegalAccessException |
InstantiationException x) {
throw new ServiceConfigurationError(null, x);
}
}
static void invoke(Method m, Object... args) throws IOException {
try {
m.invoke(null, args);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException)
throw (RuntimeException)t;
private static XmlPropertiesProvider loadProviderAsService(ClassLoader cl) {
Iterator<XmlPropertiesProvider> iterator =
ServiceLoader.load(XmlPropertiesProvider.class, cl).iterator();
return iterator.hasNext() ? iterator.next() : null;
}
if (t instanceof IOException) {
throw (IOException)t;
} else {
throw new AssertionError(t);
}
}
private static XmlPropertiesProvider loadProvider() {
return AccessController.doPrivileged(
new PrivilegedAction<XmlPropertiesProvider>() {
public XmlPropertiesProvider run() {
ClassLoader cl = ClassLoader.getSystemClassLoader();
XmlPropertiesProvider provider = loadProviderFromProperty(cl);
if (provider != null)
return provider;
provider = loadProviderAsService(cl);
if (provider != null)
return provider;
throw new InternalError("No fallback");
}});
}
private static final XmlPropertiesProvider PROVIDER = loadProvider();
static void load(Properties props, InputStream in)
throws IOException, InvalidPropertiesFormatException
{
if (load == null)
throw new InternalError("sun.util.xml.XMLUtils not found");
invoke(load, props, in);
PROVIDER.load(props, in);
}
static void save(Properties props, OutputStream os, String comment,
String encoding)
throws IOException
{
if (save == null)
throw new InternalError("sun.util.xml.XMLUtils not found");
invoke(save, props, os, comment, encoding);
PROVIDER.store(props, os, comment, encoding);
}
}
}
/*
* 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 sun.util.spi;
import java.util.Properties;
import java.util.InvalidPropertiesFormatException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
/**
* Service-provider class for loading and storing {@link Properites} in XML
* format.
*
* @see Properties#loadFromXML
* @see Properties#storeToXML
*/
public abstract class XmlPropertiesProvider {
/**
* Initializes a new instance of this class.
*/
protected XmlPropertiesProvider() {
// do nothing for now
}
/**
* Loads all of the properties represented by the XML document on the
* specified input stream into a properties table.
*
* @param props the properties table to populate
* @param in the input stream from which to read the XML document
* @throws IOException if reading from the specified input stream fails
* @throws InvalidPropertiesFormatException Data on input stream does not
* constitute a valid XML document with the mandated document type.
*
* @see Properties#loadFromXML
*/
public abstract void load(Properties props, InputStream in)
throws IOException, InvalidPropertiesFormatException;
/**
* Emits an XML document representing all of the properties in a given
* table.
*
* @param props the properies to store
* @param out the output stream on which to emit the XML document.
* @param comment a description of the property list, can be @{code null}
* @param encoding the name of a supported character encoding
*
* @throws IOException if writing to the specified output stream fails
* @throws NullPointerException if {@code out} is null.
* @throws ClassCastException if this {@code Properties} object
* contains any keys or values that are not
* {@code Strings}.
*
* @see Properties#storeToXML
*/
public abstract void store(Properties props, OutputStream out,
String comment, String encoding)
throws IOException;
}
......@@ -28,22 +28,22 @@ package sun.util.xml;
import java.io.*;
import java.util.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import org.w3c.dom.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import sun.util.spi.XmlPropertiesProvider;
/**
* A class used to aid in Properties load and save in XML. Keeping this
* code outside of Properties helps reduce the number of classes loaded
* when Properties is loaded.
* A {@code XmlPropertiesProvider} implementation that uses the JAXP API
* for parsing.
*
* @author Michael McCloskey
* @since 1.3
*/
public class XMLUtils {
public class PlatformXmlPropertiesProvider extends XmlPropertiesProvider {
// XML loading and saving methods for Properties
......@@ -67,7 +67,8 @@ public class XMLUtils {
*/
private static final String EXTERNAL_XML_VERSION = "1.0";
public static void load(Properties props, InputStream in)
@Override
public void load(Properties props, InputStream in)
throws IOException, InvalidPropertiesFormatException
{
Document doc = null;
......@@ -121,8 +122,9 @@ public class XMLUtils {
}
}
public static void save(Properties props, OutputStream os, String comment,
String encoding)
@Override
public void store(Properties props, OutputStream os, String comment,
String encoding)
throws IOException
{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
......@@ -172,9 +174,7 @@ public class XMLUtils {
try {
t.transform(doms, sr);
} catch (TransformerException te) {
IOException ioe = new IOException();
ioe.initCause(te);
throw ioe;
throw new IOException(te);
}
}
......
/*
* 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 8000354
* @summary Test
* @compile -XDignore.symbol.file CustomProvider.java MyXmlPropertiesProvider.java
* @run main/othervm -Dsun.util.spi.XmlPropertiesProvider=MyXmlPropertiesProvider CustomProvider
*/
import java.util.*;
import java.io.*;
/**
* Sanity test to verify that the property sun.util.spi.XmlPropertiesProvider
* can be used to specify a custom provider for loading/storing properties
* in XML format.
*/
public class CustomProvider {
public static void main(String[] args) throws IOException {
String provider = System.getProperty("sun.util.spi.XmlPropertiesProvider");
assertTrue(provider != null, "sun.util.spi.XmlPropertiesProvider not set");
OutputStream out = new ByteArrayOutputStream();
InputStream in = new ByteArrayInputStream(new byte[100]);
Properties props;
props = new Properties();
props.loadFromXML(in);
props = System.getProperties();
props.storeToXML(out, "comment");
props.storeToXML(out, "comment", "UTF-8");
// check that the provider's load and store methods have been invoked
assertTrue(MyXmlPropertiesProvider.createCount() == 1,
"Provider should only be created once");
assertTrue(MyXmlPropertiesProvider.loadCount() == 1,
"load method expected to be called once");
assertTrue(MyXmlPropertiesProvider.storeCount() == 2,
"store method expected to be called twice");
}
static void assertTrue(boolean b, String msg) {
if (!b) throw new RuntimeException(msg);
}
}
/*
* 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 8000354
* @summary Basic test of storeToXML and loadToXML
*/
import java.io.*;
import java.util.*;
import java.security.*;
public class LoadAndStoreXML {
/**
* Simple policy implementation that grants a set of permissions to
* all code sources and protection domains.
*/
static class SimplePolicy extends Policy {
private final Permissions perms;
public SimplePolicy(Permission...permissions) {
perms = new Permissions();
for (Permission permission : permissions)
perms.add(permission);
}
@Override
public PermissionCollection getPermissions(CodeSource cs) {
return perms;
}
@Override
public PermissionCollection getPermissions(ProtectionDomain pd) {
return perms;
}
@Override
public boolean implies(ProtectionDomain pd, Permission p) {
return perms.implies(p);
}
}
/**
* Sanity test that properties saved with Properties#storeToXML can be
* read with Properties#loadFromXML.
*/
static void test() throws IOException {
Properties props = new Properties();
props.put("k1", "foo");
props.put("k2", "bar");
ByteArrayOutputStream out = new ByteArrayOutputStream();
props.storeToXML(out, "no comment");
Properties p = new Properties();
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
p.loadFromXML(in);
if (!p.equals(props)) {
System.err.println("stored: " + props);
System.err.println("loaded: " + p);
throw new RuntimeException("Test failed");
}
}
public static void main(String[] args) throws IOException {
// run test without security manager
test();
// re-run test with security manager
Policy orig = Policy.getPolicy();
Policy p = new SimplePolicy(new RuntimePermission("setSecurityManager"),
new PropertyPermission("line.separator", "read"));
Policy.setPolicy(p);
System.setSecurityManager(new SecurityManager());
try {
test();
} finally {
// turn off security manager and restore policy
System.setSecurityManager(null);
Policy.setPolicy(orig);
}
}
}
/*
* 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.
*/
import java.util.*;
import java.io.*;
public class MyXmlPropertiesProvider
extends sun.util.spi.XmlPropertiesProvider
{
private static int createCount;
private static int loadCount;
private static int storeCount;
static int createCount() { return createCount; }
static int loadCount() { return loadCount; }
static int storeCount() { return storeCount; }
public MyXmlPropertiesProvider() {
createCount++;
}
@Override
public void load(Properties props, InputStream in)
throws IOException, InvalidPropertiesFormatException
{
loadCount++;
}
@Override
public void store(Properties props, OutputStream out,
String comment, String encoding)
throws IOException
{
storeCount++;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册