001 /*
002 * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.util;
027
028 import java.io.*;
029 import org.xml.sax.*;
030 import org.xml.sax.helpers.*;
031 import org.w3c.dom.*;
032 import javax.xml.parsers.*;
033 import javax.xml.transform.*;
034 import javax.xml.transform.dom.*;
035 import javax.xml.transform.stream.*;
036
037 /**
038 * A class used to aid in Properties load and save in XML. Keeping this
039 * code outside of Properties helps reduce the number of classes loaded
040 * when Properties is loaded.
041 *
042 * @version 1.9, 01/23/03
043 * @author Michael McCloskey
044 * @since 1.3
045 */
046 class XMLUtils {
047
048 // XML loading and saving methods for Properties
049
050 // The required DTD URI for exported properties
051 private static final String PROPS_DTD_URI = "http://java.sun.com/dtd/properties.dtd";
052
053 private static final String PROPS_DTD = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
054 + "<!-- DTD for properties -->"
055 + "<!ELEMENT properties ( comment?, entry* ) >"
056 + "<!ATTLIST properties"
057 + " version CDATA #FIXED \"1.0\">"
058 + "<!ELEMENT comment (#PCDATA) >"
059 + "<!ELEMENT entry (#PCDATA) >"
060 + "<!ATTLIST entry "
061 + " key CDATA #REQUIRED>";
062
063 /**
064 * Version number for the format of exported properties files.
065 */
066 private static final String EXTERNAL_XML_VERSION = "1.0";
067
068 static void load(Properties props, InputStream in)
069 throws IOException, InvalidPropertiesFormatException {
070 Document doc = null;
071 try {
072 doc = getLoadingDoc(in);
073 } catch (SAXException saxe) {
074 throw new InvalidPropertiesFormatException(saxe);
075 }
076 Element propertiesElement = (Element) doc.getChildNodes().item(
077 1);
078 String xmlVersion = propertiesElement.getAttribute("version");
079 if (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0)
080 throw new InvalidPropertiesFormatException(
081 "Exported Properties file format version "
082 + xmlVersion
083 + " is not supported. This java installation can read"
084 + " versions "
085 + EXTERNAL_XML_VERSION
086 + " or older. You"
087 + " may need to install a newer version of JDK.");
088 importProperties(props, propertiesElement);
089 }
090
091 static Document getLoadingDoc(InputStream in) throws SAXException,
092 IOException {
093 DocumentBuilderFactory dbf = DocumentBuilderFactory
094 .newInstance();
095 dbf.setIgnoringElementContentWhitespace(true);
096 dbf.setValidating(true);
097 dbf.setCoalescing(true);
098 dbf.setIgnoringComments(true);
099 try {
100 DocumentBuilder db = dbf.newDocumentBuilder();
101 db.setEntityResolver(new Resolver());
102 db.setErrorHandler(new EH());
103 InputSource is = new InputSource(in);
104 return db.parse(is);
105 } catch (ParserConfigurationException x) {
106 throw new Error(x);
107 }
108 }
109
110 static void importProperties(Properties props,
111 Element propertiesElement) {
112 NodeList entries = propertiesElement.getChildNodes();
113 int numEntries = entries.getLength();
114 int start = numEntries > 0
115 && entries.item(0).getNodeName().equals("comment") ? 1
116 : 0;
117 for (int i = start; i < numEntries; i++) {
118 Element entry = (Element) entries.item(i);
119 if (entry.hasAttribute("key")) {
120 Node n = entry.getFirstChild();
121 String val = (n == null) ? "" : n.getNodeValue();
122 props.setProperty(entry.getAttribute("key"), val);
123 }
124 }
125 }
126
127 static void save(Properties props, OutputStream os, String comment,
128 String encoding) throws IOException {
129 DocumentBuilderFactory dbf = DocumentBuilderFactory
130 .newInstance();
131 DocumentBuilder db = null;
132 try {
133 db = dbf.newDocumentBuilder();
134 } catch (ParserConfigurationException pce) {
135 assert (false);
136 }
137 Document doc = db.newDocument();
138 Element properties = (Element) doc.appendChild(doc
139 .createElement("properties"));
140
141 if (comment != null) {
142 Element comments = (Element) properties.appendChild(doc
143 .createElement("comment"));
144 comments.appendChild(doc.createTextNode(comment));
145 }
146
147 Set keys = props.keySet();
148 Iterator i = keys.iterator();
149 while (i.hasNext()) {
150 String key = (String) i.next();
151 Element entry = (Element) properties.appendChild(doc
152 .createElement("entry"));
153 entry.setAttribute("key", key);
154 entry.appendChild(doc
155 .createTextNode(props.getProperty(key)));
156 }
157 emitDocument(doc, os, encoding);
158 }
159
160 static void emitDocument(Document doc, OutputStream os,
161 String encoding) throws IOException {
162 TransformerFactory tf = TransformerFactory.newInstance();
163 Transformer t = null;
164 try {
165 t = tf.newTransformer();
166 t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
167 PROPS_DTD_URI);
168 t.setOutputProperty(OutputKeys.INDENT, "yes");
169 t.setOutputProperty(OutputKeys.METHOD, "xml");
170 t.setOutputProperty(OutputKeys.ENCODING, encoding);
171 } catch (TransformerConfigurationException tce) {
172 assert (false);
173 }
174 DOMSource doms = new DOMSource(doc);
175 StreamResult sr = new StreamResult(os);
176 try {
177 t.transform(doms, sr);
178 } catch (TransformerException te) {
179 IOException ioe = new IOException();
180 ioe.initCause(te);
181 throw ioe;
182 }
183 }
184
185 private static class Resolver implements EntityResolver {
186 public InputSource resolveEntity(String pid, String sid)
187 throws SAXException {
188 if (sid.equals(PROPS_DTD_URI)) {
189 InputSource is;
190 is = new InputSource(new StringReader(PROPS_DTD));
191 is.setSystemId(PROPS_DTD_URI);
192 return is;
193 }
194 throw new SAXException("Invalid system identifier: " + sid);
195 }
196 }
197
198 private static class EH implements ErrorHandler {
199 public void error(SAXParseException x) throws SAXException {
200 throw x;
201 }
202
203 public void fatalError(SAXParseException x) throws SAXException {
204 throw x;
205 }
206
207 public void warning(SAXParseException x) throws SAXException {
208 throw x;
209 }
210 }
211
212 }
|