|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  */ | 
|  |  | 
|  | package sun.util.xml; | 
|  |  | 
|  | import java.io.*; | 
|  | import java.util.*; | 
|  | import java.nio.charset.*; | 
|  | import java.util.Map.Entry; | 
|  | import org.xml.sax.*; | 
|  | 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; | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  */ | 
|  | public class PlatformXmlPropertiesProvider extends XmlPropertiesProvider { | 
|  |  | 
|  |     // XML loading and saving methods for Properties | 
|  |  | 
|  |      | 
|  |     private static final String PROPS_DTD_URI = | 
|  |     "http://java.sun.com/dtd/properties.dtd"; | 
|  |  | 
|  |     private static final String PROPS_DTD = | 
|  |     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + | 
|  |     "<!-- DTD for properties -->"                + | 
|  |     "<!ELEMENT properties ( comment?, entry* ) >"+ | 
|  |     "<!ATTLIST properties"                       + | 
|  |         " version CDATA #FIXED \"1.0\">"         + | 
|  |     "<!ELEMENT comment (#PCDATA) >"              + | 
|  |     "<!ELEMENT entry (#PCDATA) >"                + | 
|  |     "<!ATTLIST entry "                           + | 
|  |         " key CDATA #REQUIRED>"; | 
|  |  | 
|  |      | 
|  |  | 
|  |      */ | 
|  |     private static final String EXTERNAL_XML_VERSION = "1.0"; | 
|  |  | 
|  |     @Override | 
|  |     public void load(Properties props, InputStream in) | 
|  |         throws IOException, InvalidPropertiesFormatException | 
|  |     { | 
|  |         Document doc = null; | 
|  |         try { | 
|  |             doc = getLoadingDoc(in); | 
|  |         } catch (SAXException saxe) { | 
|  |             throw new InvalidPropertiesFormatException(saxe); | 
|  |         } | 
|  |         Element propertiesElement = doc.getDocumentElement(); | 
|  |         String xmlVersion = propertiesElement.getAttribute("version"); | 
|  |         if (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0) | 
|  |             throw new InvalidPropertiesFormatException( | 
|  |                 "Exported Properties file format version " + xmlVersion + | 
|  |                 " is not supported. This java installation can read" + | 
|  |                 " versions " + EXTERNAL_XML_VERSION + " or older. You" + | 
|  |                 " may need to install a newer version of JDK."); | 
|  |         importProperties(props, propertiesElement); | 
|  |     } | 
|  |  | 
|  |     static Document getLoadingDoc(InputStream in) | 
|  |         throws SAXException, IOException | 
|  |     { | 
|  |         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); | 
|  |         dbf.setIgnoringElementContentWhitespace(true); | 
|  |         dbf.setValidating(true); | 
|  |         dbf.setCoalescing(true); | 
|  |         dbf.setIgnoringComments(true); | 
|  |         try { | 
|  |             DocumentBuilder db = dbf.newDocumentBuilder(); | 
|  |             db.setEntityResolver(new Resolver()); | 
|  |             db.setErrorHandler(new EH()); | 
|  |             InputSource is = new InputSource(in); | 
|  |             return db.parse(is); | 
|  |         } catch (ParserConfigurationException x) { | 
|  |             throw new Error(x); | 
|  |         } | 
|  |     } | 
|  |  | 
|  |     static void importProperties(Properties props, Element propertiesElement) { | 
|  |         NodeList entries = propertiesElement.getChildNodes(); | 
|  |         int numEntries = entries.getLength(); | 
|  |         int start = numEntries > 0 && | 
|  |             entries.item(0).getNodeName().equals("comment") ? 1 : 0; | 
|  |         for (int i=start; i<numEntries; i++) { | 
|  |             Element entry = (Element)entries.item(i); | 
|  |             if (entry.hasAttribute("key")) { | 
|  |                 Node n = entry.getFirstChild(); | 
|  |                 String val = (n == null) ? "" : n.getNodeValue(); | 
|  |                 props.setProperty(entry.getAttribute("key"), val); | 
|  |             } | 
|  |         } | 
|  |     } | 
|  |  | 
|  |     @Override | 
|  |     public void store(Properties props, OutputStream os, String comment, | 
|  |                       String encoding) | 
|  |         throws IOException | 
|  |     { | 
|  |         // fast-fail for unsupported charsets as UnsupportedEncodingException may | 
|  |          | 
|  |         try { | 
|  |             Charset.forName(encoding); | 
|  |         } catch (IllegalCharsetNameException | UnsupportedCharsetException x) { | 
|  |             throw new UnsupportedEncodingException(encoding); | 
|  |         } | 
|  |         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); | 
|  |         DocumentBuilder db = null; | 
|  |         try { | 
|  |             db = dbf.newDocumentBuilder(); | 
|  |         } catch (ParserConfigurationException pce) { | 
|  |             assert(false); | 
|  |         } | 
|  |         Document doc = db.newDocument(); | 
|  |         Element properties =  (Element) | 
|  |             doc.appendChild(doc.createElement("properties")); | 
|  |  | 
|  |         if (comment != null) { | 
|  |             Element comments = (Element)properties.appendChild( | 
|  |                 doc.createElement("comment")); | 
|  |             comments.appendChild(doc.createTextNode(comment)); | 
|  |         } | 
|  |  | 
|  |         synchronized (props) { | 
|  |             for (Entry<Object, Object> e : props.entrySet()) { | 
|  |                 final Object k = e.getKey(); | 
|  |                 final Object v = e.getValue(); | 
|  |                 if (k instanceof String && v instanceof String) { | 
|  |                     Element entry = (Element)properties.appendChild( | 
|  |                         doc.createElement("entry")); | 
|  |                     entry.setAttribute("key", (String)k); | 
|  |                     entry.appendChild(doc.createTextNode((String)v)); | 
|  |                 } | 
|  |             } | 
|  |         } | 
|  |         emitDocument(doc, os, encoding); | 
|  |     } | 
|  |  | 
|  |     static void emitDocument(Document doc, OutputStream os, String encoding) | 
|  |         throws IOException | 
|  |     { | 
|  |         TransformerFactory tf = TransformerFactory.newInstance(); | 
|  |         Transformer t = null; | 
|  |         try { | 
|  |             t = tf.newTransformer(); | 
|  |             t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, PROPS_DTD_URI); | 
|  |             t.setOutputProperty(OutputKeys.INDENT, "yes"); | 
|  |             t.setOutputProperty(OutputKeys.METHOD, "xml"); | 
|  |             t.setOutputProperty(OutputKeys.ENCODING, encoding); | 
|  |         } catch (TransformerConfigurationException tce) { | 
|  |             assert(false); | 
|  |         } | 
|  |         DOMSource doms = new DOMSource(doc); | 
|  |         StreamResult sr = new StreamResult(os); | 
|  |         try { | 
|  |             t.transform(doms, sr); | 
|  |         } catch (TransformerException te) { | 
|  |             throw new IOException(te); | 
|  |         } | 
|  |     } | 
|  |  | 
|  |     private static class Resolver implements EntityResolver { | 
|  |         public InputSource resolveEntity(String pid, String sid) | 
|  |             throws SAXException | 
|  |         { | 
|  |             if (sid.equals(PROPS_DTD_URI)) { | 
|  |                 InputSource is; | 
|  |                 is = new InputSource(new StringReader(PROPS_DTD)); | 
|  |                 is.setSystemId(PROPS_DTD_URI); | 
|  |                 return is; | 
|  |             } | 
|  |             throw new SAXException("Invalid system identifier: " + sid); | 
|  |         } | 
|  |     } | 
|  |  | 
|  |     private static class EH implements ErrorHandler { | 
|  |         public void error(SAXParseException x) throws SAXException { | 
|  |             throw x; | 
|  |         } | 
|  |         public void fatalError(SAXParseException x) throws SAXException { | 
|  |             throw x; | 
|  |         } | 
|  |         public void warning(SAXParseException x) throws SAXException { | 
|  |             throw x; | 
|  |         } | 
|  |     } | 
|  |  | 
|  | } |