1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/share/classes/java/util/XMLUtils.java Sat Dec 01 00:00:00 2007 +0000
1.3 @@ -0,0 +1,207 @@
1.4 +/*
1.5 + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Sun designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Sun in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
1.25 + * CA 95054 USA or visit www.sun.com if you need additional information or
1.26 + * have any questions.
1.27 + */
1.28 +
1.29 +package java.util;
1.30 +
1.31 +import java.io.*;
1.32 +import org.xml.sax.*;
1.33 +import org.xml.sax.helpers.*;
1.34 +import org.w3c.dom.*;
1.35 +import javax.xml.parsers.*;
1.36 +import javax.xml.transform.*;
1.37 +import javax.xml.transform.dom.*;
1.38 +import javax.xml.transform.stream.*;
1.39 +
1.40 +/**
1.41 + * A class used to aid in Properties load and save in XML. Keeping this
1.42 + * code outside of Properties helps reduce the number of classes loaded
1.43 + * when Properties is loaded.
1.44 + *
1.45 + * @author Michael McCloskey
1.46 + * @since 1.3
1.47 + */
1.48 +class XMLUtils {
1.49 +
1.50 + // XML loading and saving methods for Properties
1.51 +
1.52 + // The required DTD URI for exported properties
1.53 + private static final String PROPS_DTD_URI =
1.54 + "http://java.sun.com/dtd/properties.dtd";
1.55 +
1.56 + private static final String PROPS_DTD =
1.57 + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
1.58 + "<!-- DTD for properties -->" +
1.59 + "<!ELEMENT properties ( comment?, entry* ) >"+
1.60 + "<!ATTLIST properties" +
1.61 + " version CDATA #FIXED \"1.0\">" +
1.62 + "<!ELEMENT comment (#PCDATA) >" +
1.63 + "<!ELEMENT entry (#PCDATA) >" +
1.64 + "<!ATTLIST entry " +
1.65 + " key CDATA #REQUIRED>";
1.66 +
1.67 + /**
1.68 + * Version number for the format of exported properties files.
1.69 + */
1.70 + private static final String EXTERNAL_XML_VERSION = "1.0";
1.71 +
1.72 + static void load(Properties props, InputStream in)
1.73 + throws IOException, InvalidPropertiesFormatException
1.74 + {
1.75 + Document doc = null;
1.76 + try {
1.77 + doc = getLoadingDoc(in);
1.78 + } catch (SAXException saxe) {
1.79 + throw new InvalidPropertiesFormatException(saxe);
1.80 + }
1.81 + Element propertiesElement = (Element)doc.getChildNodes().item(1);
1.82 + String xmlVersion = propertiesElement.getAttribute("version");
1.83 + if (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0)
1.84 + throw new InvalidPropertiesFormatException(
1.85 + "Exported Properties file format version " + xmlVersion +
1.86 + " is not supported. This java installation can read" +
1.87 + " versions " + EXTERNAL_XML_VERSION + " or older. You" +
1.88 + " may need to install a newer version of JDK.");
1.89 + importProperties(props, propertiesElement);
1.90 + }
1.91 +
1.92 + static Document getLoadingDoc(InputStream in)
1.93 + throws SAXException, IOException
1.94 + {
1.95 + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1.96 + dbf.setIgnoringElementContentWhitespace(true);
1.97 + dbf.setValidating(true);
1.98 + dbf.setCoalescing(true);
1.99 + dbf.setIgnoringComments(true);
1.100 + try {
1.101 + DocumentBuilder db = dbf.newDocumentBuilder();
1.102 + db.setEntityResolver(new Resolver());
1.103 + db.setErrorHandler(new EH());
1.104 + InputSource is = new InputSource(in);
1.105 + return db.parse(is);
1.106 + } catch (ParserConfigurationException x) {
1.107 + throw new Error(x);
1.108 + }
1.109 + }
1.110 +
1.111 + static void importProperties(Properties props, Element propertiesElement) {
1.112 + NodeList entries = propertiesElement.getChildNodes();
1.113 + int numEntries = entries.getLength();
1.114 + int start = numEntries > 0 &&
1.115 + entries.item(0).getNodeName().equals("comment") ? 1 : 0;
1.116 + for (int i=start; i<numEntries; i++) {
1.117 + Element entry = (Element)entries.item(i);
1.118 + if (entry.hasAttribute("key")) {
1.119 + Node n = entry.getFirstChild();
1.120 + String val = (n == null) ? "" : n.getNodeValue();
1.121 + props.setProperty(entry.getAttribute("key"), val);
1.122 + }
1.123 + }
1.124 + }
1.125 +
1.126 + static void save(Properties props, OutputStream os, String comment,
1.127 + String encoding)
1.128 + throws IOException
1.129 + {
1.130 + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1.131 + DocumentBuilder db = null;
1.132 + try {
1.133 + db = dbf.newDocumentBuilder();
1.134 + } catch (ParserConfigurationException pce) {
1.135 + assert(false);
1.136 + }
1.137 + Document doc = db.newDocument();
1.138 + Element properties = (Element)
1.139 + doc.appendChild(doc.createElement("properties"));
1.140 +
1.141 + if (comment != null) {
1.142 + Element comments = (Element)properties.appendChild(
1.143 + doc.createElement("comment"));
1.144 + comments.appendChild(doc.createTextNode(comment));
1.145 + }
1.146 +
1.147 + Set keys = props.keySet();
1.148 + Iterator i = keys.iterator();
1.149 + while(i.hasNext()) {
1.150 + String key = (String)i.next();
1.151 + Element entry = (Element)properties.appendChild(
1.152 + doc.createElement("entry"));
1.153 + entry.setAttribute("key", key);
1.154 + entry.appendChild(doc.createTextNode(props.getProperty(key)));
1.155 + }
1.156 + emitDocument(doc, os, encoding);
1.157 + }
1.158 +
1.159 + static void emitDocument(Document doc, OutputStream os, String encoding)
1.160 + throws IOException
1.161 + {
1.162 + TransformerFactory tf = TransformerFactory.newInstance();
1.163 + Transformer t = null;
1.164 + try {
1.165 + t = tf.newTransformer();
1.166 + t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, PROPS_DTD_URI);
1.167 + t.setOutputProperty(OutputKeys.INDENT, "yes");
1.168 + t.setOutputProperty(OutputKeys.METHOD, "xml");
1.169 + t.setOutputProperty(OutputKeys.ENCODING, encoding);
1.170 + } catch (TransformerConfigurationException tce) {
1.171 + assert(false);
1.172 + }
1.173 + DOMSource doms = new DOMSource(doc);
1.174 + StreamResult sr = new StreamResult(os);
1.175 + try {
1.176 + t.transform(doms, sr);
1.177 + } catch (TransformerException te) {
1.178 + IOException ioe = new IOException();
1.179 + ioe.initCause(te);
1.180 + throw ioe;
1.181 + }
1.182 + }
1.183 +
1.184 + private static class Resolver implements EntityResolver {
1.185 + public InputSource resolveEntity(String pid, String sid)
1.186 + throws SAXException
1.187 + {
1.188 + if (sid.equals(PROPS_DTD_URI)) {
1.189 + InputSource is;
1.190 + is = new InputSource(new StringReader(PROPS_DTD));
1.191 + is.setSystemId(PROPS_DTD_URI);
1.192 + return is;
1.193 + }
1.194 + throw new SAXException("Invalid system identifier: " + sid);
1.195 + }
1.196 + }
1.197 +
1.198 + private static class EH implements ErrorHandler {
1.199 + public void error(SAXParseException x) throws SAXException {
1.200 + throw x;
1.201 + }
1.202 + public void fatalError(SAXParseException x) throws SAXException {
1.203 + throw x;
1.204 + }
1.205 + public void warning(SAXParseException x) throws SAXException {
1.206 + throw x;
1.207 + }
1.208 + }
1.209 +
1.210 +}