1. /*
  2. * @(#)XMLUtils.java 1.5 04/06/07
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.util;
  8. import java.io.*;
  9. import org.xml.sax.*;
  10. import org.xml.sax.helpers.*;
  11. import org.w3c.dom.*;
  12. import javax.xml.parsers.*;
  13. import javax.xml.transform.*;
  14. import javax.xml.transform.dom.*;
  15. import javax.xml.transform.stream.*;
  16. /**
  17. * A class used to aid in Properties load and save in XML. Keeping this
  18. * code outside of Properties helps reduce the number of classes loaded
  19. * when Properties is loaded.
  20. *
  21. * @version 1.9, 01/23/03
  22. * @author Michael McCloskey
  23. * @since 1.3
  24. */
  25. class XMLUtils {
  26. // XML loading and saving methods for Properties
  27. // The required DTD URI for exported properties
  28. private static final String PROPS_DTD_URI =
  29. "http://java.sun.com/dtd/properties.dtd";
  30. private static final String PROPS_DTD =
  31. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
  32. "<!-- DTD for properties -->" +
  33. "<!ELEMENT properties ( comment?, entry* ) >"+
  34. "<!ATTLIST properties" +
  35. " version CDATA #FIXED \"1.0\">" +
  36. "<!ELEMENT comment (#PCDATA) >" +
  37. "<!ELEMENT entry (#PCDATA) >" +
  38. "<!ATTLIST entry " +
  39. " key CDATA #REQUIRED>";
  40. /**
  41. * Version number for the format of exported properties files.
  42. */
  43. private static final String EXTERNAL_XML_VERSION = "1.0";
  44. static void load(Properties props, InputStream in)
  45. throws IOException, InvalidPropertiesFormatException
  46. {
  47. Document doc = null;
  48. try {
  49. doc = getLoadingDoc(in);
  50. } catch (SAXException saxe) {
  51. throw new InvalidPropertiesFormatException(saxe);
  52. }
  53. Element propertiesElement = (Element)doc.getChildNodes().item(1);
  54. String xmlVersion = propertiesElement.getAttribute("version");
  55. if (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0)
  56. throw new InvalidPropertiesFormatException(
  57. "Exported Properties file format version " + xmlVersion +
  58. " is not supported. This java installation can read" +
  59. " versions " + EXTERNAL_XML_VERSION + " or older. You" +
  60. " may need to install a newer version of JDK.");
  61. importProperties(props, propertiesElement);
  62. }
  63. static Document getLoadingDoc(InputStream in)
  64. throws SAXException, IOException
  65. {
  66. DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  67. dbf.setIgnoringElementContentWhitespace(true);
  68. dbf.setValidating(true);
  69. dbf.setCoalescing(true);
  70. dbf.setIgnoringComments(true);
  71. try {
  72. DocumentBuilder db = dbf.newDocumentBuilder();
  73. db.setEntityResolver(new Resolver());
  74. db.setErrorHandler(new EH());
  75. InputSource is = new InputSource(in);
  76. return db.parse(is);
  77. } catch (ParserConfigurationException x) {
  78. throw new Error(x);
  79. }
  80. }
  81. static void importProperties(Properties props, Element propertiesElement) {
  82. NodeList entries = propertiesElement.getChildNodes();
  83. int numEntries = entries.getLength();
  84. int start = numEntries > 0 &&
  85. entries.item(0).getNodeName().equals("comment") ? 1 : 0;
  86. for (int i=start; i<numEntries; i++) {
  87. Element entry = (Element)entries.item(i);
  88. if (entry.hasAttribute("key")) {
  89. Node n = entry.getFirstChild();
  90. String val = (n == null) ? "" : n.getNodeValue();
  91. props.setProperty(entry.getAttribute("key"), val);
  92. }
  93. }
  94. }
  95. static void save(Properties props, OutputStream os, String comment,
  96. String encoding)
  97. throws IOException
  98. {
  99. DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  100. DocumentBuilder db = null;
  101. try {
  102. db = dbf.newDocumentBuilder();
  103. } catch (ParserConfigurationException pce) {
  104. assert(false);
  105. }
  106. Document doc = db.newDocument();
  107. Element properties = (Element)
  108. doc.appendChild(doc.createElement("properties"));
  109. if (comment != null) {
  110. Element comments = (Element)properties.appendChild(
  111. doc.createElement("comment"));
  112. comments.appendChild(doc.createTextNode(comment));
  113. }
  114. Set keys = props.keySet();
  115. Iterator i = keys.iterator();
  116. while(i.hasNext()) {
  117. String key = (String)i.next();
  118. Element entry = (Element)properties.appendChild(
  119. doc.createElement("entry"));
  120. entry.setAttribute("key", key);
  121. entry.appendChild(doc.createTextNode(props.getProperty(key)));
  122. }
  123. emitDocument(doc, os, encoding);
  124. }
  125. static void emitDocument(Document doc, OutputStream os, String encoding)
  126. throws IOException
  127. {
  128. TransformerFactory tf = TransformerFactory.newInstance();
  129. Transformer t = null;
  130. try {
  131. t = tf.newTransformer();
  132. t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, PROPS_DTD_URI);
  133. t.setOutputProperty(OutputKeys.INDENT, "yes");
  134. t.setOutputProperty(OutputKeys.METHOD, "xml");
  135. t.setOutputProperty(OutputKeys.ENCODING, encoding);
  136. } catch (TransformerConfigurationException tce) {
  137. assert(false);
  138. }
  139. DOMSource doms = new DOMSource(doc);
  140. StreamResult sr = new StreamResult(os);
  141. try {
  142. t.transform(doms, sr);
  143. } catch (TransformerException te) {
  144. IOException ioe = new IOException();
  145. ioe.initCause(te);
  146. throw ioe;
  147. }
  148. }
  149. private static class Resolver implements EntityResolver {
  150. public InputSource resolveEntity(String pid, String sid)
  151. throws SAXException
  152. {
  153. if (sid.equals(PROPS_DTD_URI)) {
  154. InputSource is;
  155. is = new InputSource(new StringReader(PROPS_DTD));
  156. is.setSystemId(PROPS_DTD_URI);
  157. return is;
  158. }
  159. throw new SAXException("Invalid system identifier: " + sid);
  160. }
  161. }
  162. private static class EH implements ErrorHandler {
  163. public void error(SAXParseException x) throws SAXException {
  164. throw x;
  165. }
  166. public void fatalError(SAXParseException x) throws SAXException {
  167. throw x;
  168. }
  169. public void warning(SAXParseException x) throws SAXException {
  170. throw x;
  171. }
  172. }
  173. }