# HG changeset patch # User Jaroslav Tulach # Date 1245857369 -7200 # Node ID 24b6c30fbf71a1743ab78504415a1c013985558f # Parent 52864f10883d0cd9d638a9428db8256586ae9729 Simple output of Preferences is the same as the original one via DOM diff -r 52864f10883d -r 24b6c30fbf71 build.xml --- a/build.xml Wed Jun 24 16:38:24 2009 +0200 +++ b/build.xml Wed Jun 24 17:29:29 2009 +0200 @@ -373,6 +373,12 @@ > + + + @@ -381,6 +387,13 @@ + + + + + + + diff -r 52864f10883d -r 24b6c30fbf71 src/share/classes/sun/util/xml/DefaultPrefsXmlSupport.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/util/xml/DefaultPrefsXmlSupport.java Wed Jun 24 17:29:29 2009 +0200 @@ -0,0 +1,385 @@ +/* + * Copyright 2002-2006 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.util.xml; + +import java.util.*; +import java.util.prefs.*; +import java.io.*; + +/** + * Simplified XML Support for java.util.prefs. Methods to import and export preference + * nodes and subtrees. + * + * @author Jaroslav Tulach + * @since 1.7 + */ +public class DefaultPrefsXmlSupport extends sun.util.xml.PrefsXmlSupport { + public void export(OutputStream os, final Preferences p, boolean subTree) + throws IOException, BackingStoreException { + if (isRemoved(p)) + throw new IllegalStateException("Node has been removed"); + PrintWriter w = new PrintWriter(new OutputStreamWriter(os, "UTF-8")); + w.println(""); + w.println(""); + w.println(""); + w.print(" "); + LinkedList ancestors = new LinkedList(); + for (Preferences kid = p, dad = kid.parent(); dad != null; + kid = dad, dad = kid.parent()) { + ancestors.addFirst(kid); + } + String indent = " "; + for (Preferences pref : ancestors) { + indent = " " + indent; + w.print(indent); w.println(""); + w.print(indent); w.print(""); + } + + putPreferencesInXml(w, indent + " ", p, subTree); + for (Preferences pref : ancestors) { + w.print(indent); w.println(""); + indent = indent.substring(2); + } + + w.println(" "); + w.println(""); + w.flush(); + } + + private static void putPreferencesInXml( + PrintWriter w, String indent, Preferences prefs, boolean subTree + ) throws BackingStoreException { + Preferences[] kidsCopy = null; + String[] kidNames = null; + + // Node is locked to export its contents and get a + // copy of children, then lock is released, + // and, if subTree = true, recursive calls are made on children + synchronized (lock(prefs)) { + // Check if this node was concurrently removed. If yes + // don't print it + if (isRemoved(prefs)) { + return; + } + // Put map in xml element + String[] keys = prefs.keys(); + if (keys.length == 0) { + w.print(indent); w.println(""); + } else { + w.print(indent); w.println(""); + for (int i=0; i"); + } + w.print(indent); w.println(""); + } + // Recurse if appropriate + if (subTree) { + /* Get a copy of kids while lock is held */ + kidNames = prefs.childrenNames(); + kidsCopy = new Preferences[kidNames.length]; + for (int i = 0; i < kidNames.length; i++) + kidsCopy[i] = prefs.node(kidNames[i]); + } + // release lock + } + + if (subTree) { + for (int i=0; i < kidNames.length; i++) { + w.print(indent); w.print(""); + putPreferencesInXml(w, " " + indent, kidsCopy[i], subTree); + w.print(indent); w.println(""); + } + } + } + + /** + * Import preferences from the specified input stream, which is assumed + * to contain an XML document in the format described in the Preferences + * spec. + * + * @throws IOException if reading from the specified output stream + * results in an IOException. + * @throws InvalidPreferencesFormatException Data on input stream does not + * constitute a valid XML document with the mandated document type. + */ + public void importPreferences(InputStream is) + throws IOException, InvalidPreferencesFormatException + { + /* + try { + Document doc = loadPrefsDoc(is); + String xmlVersion = + doc.getDocumentElement().getAttribute("EXTERNAL_XML_VERSION"); + if (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0) + throw new InvalidPreferencesFormatException( + "Exported preferences 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."); + + Element xmlRoot = (Element) doc.getDocumentElement(). + getChildNodes().item(0); + Preferences prefsRoot = + (xmlRoot.getAttribute("type").equals("user") ? + Preferences.userRoot() : Preferences.systemRoot()); + ImportSubtree(prefsRoot, xmlRoot); + } catch(SAXException e) { + throw new InvalidPreferencesFormatException(e); + } + */ + } + + /** + * Create a new prefs XML document. + * + private static Document createPrefsDoc( String qname ) { + try { + DOMImplementation di = DocumentBuilderFactory.newInstance(). + newDocumentBuilder().getDOMImplementation(); + DocumentType dt = di.createDocumentType(qname, null, PREFS_DTD_URI); + return di.createDocument(null, qname, dt); + } catch(ParserConfigurationException e) { + throw new AssertionError(e); + } + } + + /** + * Load an XML document from specified input stream, which must + * have the requisite DTD URI. + * + private static Document loadPrefsDoc(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()); + return db.parse(new InputSource(in)); + } catch (ParserConfigurationException e) { + throw new AssertionError(e); + } + } + + /** + * Write XML document to the specified output stream. + * + private static final void writeDoc(Document doc, OutputStream out) + throws IOException + { + try { + TransformerFactory tf = TransformerFactory.newInstance(); + try { + tf.setAttribute("indent-number", new Integer(2)); + } catch (IllegalArgumentException iae) { + //Ignore the IAE. Should not fail the writeout even the + //transformer provider does not support "indent-number". + } + Transformer t = tf.newTransformer(); + t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId()); + t.setOutputProperty(OutputKeys.INDENT, "yes"); + //Transformer resets the "indent" info if the "result" is a StreamResult with + //an OutputStream object embedded, creating a Writer object on top of that + //OutputStream object however works. + t.transform(new DOMSource(doc), + new StreamResult(new BufferedWriter(new OutputStreamWriter(out, "UTF-8")))); + } catch(TransformerException e) { + throw new AssertionError(e); + } + } + + /** + * Recursively traverse the specified preferences node and store + * the described preferences into the system or current user + * preferences tree, as appropriate. + * + private static void ImportSubtree(Preferences prefsNode, Element xmlNode) { + NodeList xmlKids = xmlNode.getChildNodes(); + int numXmlKids = xmlKids.getLength(); + /* + * We first lock the node, import its contents and get + * child nodes. Then we unlock the node and go to children + * Since some of the children might have been concurrently + * deleted we check for this. + * / + Preferences[] prefsKids; + /* Lock the node * / + synchronized (lock(prefsNode)) { + //If removed, return silently + if (isRemoved(prefsNode)) + return; + + // Import any preferences at this node + Element firstXmlKid = (Element) xmlKids.item(0); + ImportPrefs(prefsNode, firstXmlKid); + prefsKids = new Preferences[numXmlKids - 1]; + + // Get involved children + for (int i=1; i < numXmlKids; i++) { + Element xmlKid = (Element) xmlKids.item(i); + prefsKids[i-1] = prefsNode.node(xmlKid.getAttribute("name")); + } + } // unlocked the node + // import children + for (int i=1; i < numXmlKids; i++) + ImportSubtree(prefsKids[i-1], (Element)xmlKids.item(i)); + } + + /** + * Import the preferences described by the specified XML element + * (a map from a preferences document) into the specified + * preferences node. + * / + private static void ImportPrefs(Preferences prefsNode, Element map) { + NodeList entries = map.getChildNodes(); + for (int i=0, numEntries = entries.getLength(); i < numEntries; i++) { + Element entry = (Element) entries.item(i); + prefsNode.put(entry.getAttribute("key"), + entry.getAttribute("value")); + } + } + + /** + * Export the specified Map to a map document on + * the specified OutputStream as per the prefs DTD. This is used + * as the internal (undocumented) format for FileSystemPrefs. + * + * @throws IOException if writing to the specified output stream + * results in an IOException. + */ + public void exportMap(OutputStream os, Map map) throws IOException { + /* + Document doc = createPrefsDoc("map"); + Element xmlMap = doc.getDocumentElement( ) ; + xmlMap.setAttribute("MAP_XML_VERSION", MAP_XML_VERSION); + + for (Iterator i = map.entrySet().iterator(); i.hasNext(); ) { + Map.Entry e = (Map.Entry) i.next(); + Element xe = (Element) + xmlMap.appendChild(doc.createElement("entry")); + xe.setAttribute("key", (String) e.getKey()); + xe.setAttribute("value", (String) e.getValue()); + } + + writeDoc(doc, os); + */ + } + + /** + * Import Map from the specified input stream, which is assumed + * to contain a map document as per the prefs DTD. This is used + * as the internal (undocumented) format for FileSystemPrefs. The + * key-value pairs specified in the XML document will be put into + * the specified Map. (If this Map is empty, it will contain exactly + * the key-value pairs int the XML-document when this method returns.) + * + * @throws IOException if reading from the specified output stream + * results in an IOException. + * @throws InvalidPreferencesFormatException Data on input stream does not + * constitute a valid XML document with the mandated document type. + */ + public void importMap(InputStream is, Map m) + throws IOException, InvalidPreferencesFormatException + { + /* + try { + Document doc = loadPrefsDoc(is); + Element xmlMap = doc.getDocumentElement(); + // check version + String mapVersion = xmlMap.getAttribute("MAP_XML_VERSION"); + if (mapVersion.compareTo(MAP_XML_VERSION) > 0) + throw new InvalidPreferencesFormatException( + "Preferences map file format version " + mapVersion + + " is not supported. This java installation can read" + + " versions " + MAP_XML_VERSION + " or older. You may need" + + " to install a newer version of JDK."); + + NodeList entries = xmlMap.getChildNodes(); + for (int i=0, numEntries=entries.getLength(); i it = ServiceLoader.load(PrefsXmlSupport.class).iterator(); - return it.hasNext() ? it.next() : null /* JST-XXX: some default */; + return it.hasNext() ? it.next() : new DefaultPrefsXmlSupport(); } public abstract void export(OutputStream os, final Preferences p, boolean subTree) diff -r 52864f10883d -r 24b6c30fbf71 test/java/util/prefs/Preferences/XMLPreferencesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/prefs/Preferences/XMLPreferencesTest.java Wed Jun 24 17:29:29 2009 +0200 @@ -0,0 +1,97 @@ +/* + * Copyright 2002-2006 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + + +import java.io.ByteArrayInputStream; +import sun.util.xml.PrefsXmlSupport; + +import java.io.ByteArrayOutputStream; +import java.util.prefs.Preferences; + +/** Checks whether reading and writing via standard DOM and simplified API + * results in same results. + * + * @author Jaroslav Tulach + */ +public class XMLPreferencesTest { + private static PrefsXmlSupport FULL = new com.sun.xml.internal.PrefsXmlSupportImpl(); + private static PrefsXmlSupport SIMPLE = new sun.util.xml.DefaultPrefsXmlSupport(); + + + public static void main(String[] args) throws Exception { + XMLPreferencesTest test = new XMLPreferencesTest(); + test.testCompareOutput(); + test.testCompareInput(); + } + + + public XMLPreferencesTest() { + } + + public void testCompareOutput() throws Exception { + Preferences p = Preferences.userRoot().node("a/b/c"); + p.put("ahoj", "simple"); + p.putInt("kuk", 1); + p.putBoolean("multi", true); + p.node("child").putBoolean("data", false); + p.node("empty"); + p.parent().putDouble("visible", 1.0); + + ByteArrayOutputStream full = new ByteArrayOutputStream(); + FULL.export(full, p, true); + + ByteArrayOutputStream simple = new ByteArrayOutputStream(); + SIMPLE.export(simple, p, true); + if (full.toString().equals(simple.toString())) { + // OK + System.err.println("OK: testCompareOutput"); + } else { + assert false : + "Full version differs from simplified. Full:\n" + full + "\nSimple:\n" + simple; + } + } + + public void testCompareInput() throws Exception { + /* + String text = ""; + + Properties p1 = new Properties(); + { + ByteArrayInputStream is = new ByteArrayInputStream(text.getBytes("UTF-8")); + FULL.load(p1, is); + } + + Properties p2 = new Properties(); + { + ByteArrayInputStream is = new ByteArrayInputStream(text.getBytes("UTF-8")); + SIMPLE.load(p2, is); + } + + assert p1.equals(p2) : "P1: " + p1 + "\nP2: " + p2; + System.err.println("OK: testCompareInput"); + */ + } + +} \ No newline at end of file