FileDocCategorySizeDatePackage
XmlSupport.javaAPI DocJava SE 6 API16460Tue Jun 10 00:26:00 BST 2008java.util.prefs

XmlSupport

public class XmlSupport extends Object
XML Support for java.util.prefs. Methods to import and export preference nodes and subtrees.
author
Josh Bloch and Mark Reinhold
version
1.10, 11/17/05
see
Preferences
since
1.4

Fields Summary
private static final String
PREFS_DTD_URI
private static final String
PREFS_DTD
private static final String
EXTERNAL_XML_VERSION
Version number for the format exported preferences files.
private static final String
MAP_XML_VERSION
Constructors Summary
Methods Summary
private static voidImportPrefs(java.util.prefs.Preferences prefsNode, org.w3c.dom.Element map)
Import the preferences described by the specified XML element (a map from a preferences document) into the specified preferences node.

        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"));
        }
    
private static voidImportSubtree(java.util.prefs.Preferences prefsNode, org.w3c.dom.Element xmlNode)
Recursively traverse the specified preferences node and store the described preferences into the system or current user preferences tree, as appropriate.

        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 (((AbstractPreferences)prefsNode).lock) {
            //If removed, return silently 
            if (((AbstractPreferences)prefsNode).isRemoved())
                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));
    
private static org.w3c.dom.DocumentcreatePrefsDoc(java.lang.String qname)
Create a new prefs XML document.

        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);
        }
    
static voidexport(java.io.OutputStream os, java.util.prefs.Preferences p, boolean subTree)
Export the specified preferences node and, if subTree is true, all subnodes, to the specified output stream. Preferences are exported as an XML document conforming to the definition in the Preferences spec.

throws
IOException if writing to the specified output stream results in an IOException.
throws
BackingStoreException if preference data cannot be read from backing store.
throws
IllegalStateException if this node (or an ancestor) has been removed with the {@link #removeNode()} method.

    
                                                                                                          
            
           
        if (((AbstractPreferences)p).isRemoved()) 
            throw new IllegalStateException("Node has been removed");                
        Document doc = createPrefsDoc("preferences");
        Element preferences =  doc.getDocumentElement() ;
        preferences.setAttribute("EXTERNAL_XML_VERSION", EXTERNAL_XML_VERSION);
        Element xmlRoot =  (Element)
        preferences.appendChild(doc.createElement("root"));
        xmlRoot.setAttribute("type", (p.isUserNode() ? "user" : "system"));

        // Get bottom-up list of nodes from p to root, excluding root
        List ancestors = new ArrayList();
            
        for (Preferences kid = p, dad = kid.parent(); dad != null;
                                   kid = dad, dad = kid.parent()) {
            ancestors.add(kid);
        }
        Element e = xmlRoot;                        
        for (int i=ancestors.size()-1; i >= 0; i--) { 
            e.appendChild(doc.createElement("map"));
            e = (Element) e.appendChild(doc.createElement("node"));
            e.setAttribute("name", ((Preferences)ancestors.get(i)).name());
        }
        putPreferencesInXml(e, doc, p, subTree);

        writeDoc(doc, os);
    
static voidexportMap(java.io.OutputStream os, java.util.Map map)
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.

        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);
    
static voidimportMap(java.io.InputStream is, java.util.Map m)
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.

        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<numEntries; i++) {
                Element entry = (Element) entries.item(i);
                m.put(entry.getAttribute("key"), entry.getAttribute("value"));
            }
        } catch(SAXException e) {
            throw new InvalidPreferencesFormatException(e);
        }
    
static voidimportPreferences(java.io.InputStream is)
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.

        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);
        }
    
private static org.w3c.dom.DocumentloadPrefsDoc(java.io.InputStream in)
Load an XML document from specified input stream, which must have the requisite DTD URI.

        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);
        }
    
private static voidputPreferencesInXml(org.w3c.dom.Element elt, org.w3c.dom.Document doc, java.util.prefs.Preferences prefs, boolean subTree)
Put the preferences in the specified Preferences node into the specified XML element which is assumed to represent a node in the specified XML document which is assumed to conform to PREFS_DTD. If subTree is true, create children of the specified XML node conforming to all of the children of the specified Preferences node and recurse.

throws
BackingStoreException if it is not possible to read the preferences or children out of the specified preferences node.

   
        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 (((AbstractPreferences)prefs).lock) {
            // Check if this node was concurrently removed. If yes
            // remove it from XML Document and return.
            if (((AbstractPreferences)prefs).isRemoved()) {
                elt.getParentNode().removeChild(elt);
                return;
            }
            // Put map in xml element            
            String[] keys = prefs.keys();
            Element map = (Element) elt.appendChild(doc.createElement("map"));
            for (int i=0; i<keys.length; i++) {
                Element entry = (Element)
                    map.appendChild(doc.createElement("entry"));
                entry.setAttribute("key", keys[i]);
                // NEXT STATEMENT THROWS NULL PTR EXC INSTEAD OF ASSERT FAIL
                entry.setAttribute("value", prefs.get(keys[i], null));
            }
            // 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++) {
                Element xmlKid = (Element)
                    elt.appendChild(doc.createElement("node"));
                xmlKid.setAttribute("name", kidNames[i]);
                putPreferencesInXml(xmlKid, doc, kidsCopy[i], subTree);
            }
        }
    
private static final voidwriteDoc(org.w3c.dom.Document doc, java.io.OutputStream out)
Write XML document to the specified output stream.

        try {
            TransformerFactory tf = TransformerFactory.newInstance();
            tf.setAttribute("indent-number", new Integer(2));
            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);
        }