FileDocCategorySizeDatePackage
XMLParser.javaAPI DocAndroid 1.5 API23018Wed May 06 22:41:04 BST 2009java.util.prefs

XMLParser

public class XMLParser extends Object
Utility class for importing and exporting {@code Preferences} data from an XML file.
since
Android 1.0

Fields Summary
static final String
PREFS_DTD_NAME
static final String
PREFS_DTD
static final String
HEADER
static final String
DOCTYPE
private static final String[]
EMPTY_SARRAY
private static final String
FILE_PREFS
private static final float
XML_VERSION
private static final DocumentBuilder
builder
private static int
indent
Constructors Summary
private XMLParser()


    /*
     * init DOM builder
     */
     
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // BEGIN android-changed
        factory.setValidating(false);
        // END android-changed
        try {
            builder = factory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            throw new Error(e);
        }
        builder.setEntityResolver(new EntityResolver() {
            public InputSource resolveEntity(String publicId, String systemId)
                    throws SAXException, IOException {
                if (systemId.equals(PREFS_DTD_NAME)) {
                    InputSource result = new InputSource(new StringReader(
                            PREFS_DTD));
                    result.setSystemId(PREFS_DTD_NAME);
                    return result;
                }
                // prefs.1=Invalid DOCTYPE declaration: {0}
                throw new SAXException(
                        Messages.getString("prefs.1", systemId));  //$NON-NLS-1$
            }
        });
        builder.setErrorHandler(new ErrorHandler() {
            public void warning(SAXParseException e) throws SAXException {
                throw e;
            }

            public void error(SAXParseException e) throws SAXException {
                throw e;
            }

            public void fatalError(SAXParseException e) throws SAXException {
                throw e;
            }
        });
    // empty constructor
    
Methods Summary
private static voidexportEntries(java.util.prefs.Preferences prefs, java.io.BufferedWriter out)

        String[] keys = prefs.keys();
        String[] values = new String[keys.length];
        for (int i = 0; i < keys.length; i++) {
            values[i] = prefs.get(keys[i], null);
        }
        exportEntries(keys, values, out);
    
private static voidexportEntries(java.lang.String[] keys, java.lang.String[] values, java.io.BufferedWriter out)

        if (keys.length == 0) {
            flushEmptyElement("map", out); //$NON-NLS-1$
            return;
        }
        flushStartTag("map", out); //$NON-NLS-1$
        for (int i = 0; i < keys.length; i++) {
            if (values[i] != null) {
                flushEmptyElement(
                        "entry", new String[] { "key", "value" }, new String[] { keys[i], values[i] }, out); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
            }
        }
        flushEndTag("map", out); //$NON-NLS-1$
    
private static voidexportNode(java.util.StringTokenizer ancestors, java.util.prefs.Preferences prefs, boolean withSubTree, java.io.BufferedWriter out)

        if (ancestors.hasMoreTokens()) {
            String name = ancestors.nextToken();
            flushStartTag(
                    "node", new String[] { "name" }, new String[] { name }, out); //$NON-NLS-1$ //$NON-NLS-2$
            if (ancestors.hasMoreTokens()) {
                flushEmptyElement("map", out); //$NON-NLS-1$
                exportNode(ancestors, prefs, withSubTree, out);
            } else {
                exportEntries(prefs, out);
                if (withSubTree) {
                    exportSubTree(prefs, out);
                }
            }
            flushEndTag("node", out); //$NON-NLS-1$
        }
    
static voidexportPrefs(java.util.prefs.Preferences prefs, java.io.OutputStream stream, boolean withSubTree)
utilities for Preferences export

        indent = -1;
        // BEGIN android-modified
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(stream, "UTF-8"), 8192); //$NON-NLS-1$
        // END android-modified
        out.write(HEADER);
        out.newLine();
        out.newLine();

        out.write(DOCTYPE);
        out.write(" '"); //$NON-NLS-1$
        out.write(PREFS_DTD_NAME);
        out.write("'>"); //$NON-NLS-1$
        out.newLine();
        out.newLine();

        flushStartTag(
                "preferences", new String[] { "EXTERNAL_XML_VERSION" }, new String[] { String.valueOf(XML_VERSION) }, out); //$NON-NLS-1$ //$NON-NLS-2$
        flushStartTag(
                "root", new String[] { "type" }, new String[] { prefs.isUserNode() ? "user" : "system" }, out); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
        flushEmptyElement("map", out); //$NON-NLS-1$

        StringTokenizer ancestors = new StringTokenizer(prefs.absolutePath(),
                "/"); //$NON-NLS-1$
        exportNode(ancestors, prefs, withSubTree, out);

        flushEndTag("root", out); //$NON-NLS-1$
        flushEndTag("preferences", out); //$NON-NLS-1$
        out.flush();
        out = null;
    
private static voidexportSubTree(java.util.prefs.Preferences prefs, java.io.BufferedWriter out)

        String[] names = prefs.childrenNames();
        if (names.length > 0) {
            for (int i = 0; i < names.length; i++) {
                Preferences child = prefs.node(names[i]);
                flushStartTag(
                        "node", new String[] { "name" }, new String[] { names[i] }, out); //$NON-NLS-1$ //$NON-NLS-2$
                exportEntries(child, out);
                exportSubTree(child, out);
                flushEndTag("node", out); //$NON-NLS-1$
            }
        }
    
private static voidflushEmptyElement(java.lang.String tagName, java.io.BufferedWriter out)

        flushIndent(++indent, out);
        out.write("<"); //$NON-NLS-1$
        out.write(tagName);
        out.write(" />"); //$NON-NLS-1$
        out.newLine();
        indent--;
    
private static voidflushEmptyElement(java.lang.String tagName, java.lang.String[] attrKeys, java.lang.String[] attrValues, java.io.BufferedWriter out)

        flushIndent(++indent, out);
        out.write("<"); //$NON-NLS-1$
        out.write(tagName);
        flushPairs(attrKeys, attrValues, out);
        out.write(" />"); //$NON-NLS-1$
        out.newLine();
        indent--;
    
private static voidflushEndTag(java.lang.String tagName, java.io.BufferedWriter out)

        flushIndent(indent--, out);
        out.write("</"); //$NON-NLS-1$
        out.write(tagName);
        out.write(">"); //$NON-NLS-1$
        out.newLine();
    
static voidflushFilePrefs(java.io.File file, java.util.Properties prefs)

param
file
param
prefs
throws
PrivilegedActionException

        AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
            public Object run() throws IOException {
                flushFilePrefsImpl(file, prefs);
                return null;
            }
        });
    
static voidflushFilePrefsImpl(java.io.File file, java.util.Properties prefs)

        BufferedWriter out = null;
        FileLock lock = null;
        try {
            FileOutputStream ostream = new FileOutputStream(file);
            // BEGIN android-modified
            out = new BufferedWriter(new OutputStreamWriter(ostream, "UTF-8"), 8192); //$NON-NLS-1$
            // END android-modified
            FileChannel channel = ostream.getChannel();
            lock = channel.lock();
            out.write(HEADER);
            out.newLine();
            out.write(FILE_PREFS);
            out.newLine();
            if (prefs.size() == 0) {
                exportEntries(EMPTY_SARRAY, EMPTY_SARRAY, out);
            } else {
                String[] keys = prefs.keySet().toArray(new String[prefs.size()]);
                int length = keys.length;
                String[] values = new String[length];
                for (int i = 0; i < length; i++) {
                    values[i] = prefs.getProperty(keys[i]);
                }
                exportEntries(keys, values, out);
            }
            out.flush();
        } finally {
            try {
                lock.release();
            } catch (Exception e) {//ignore
            }
            try {
                if (null != out) {
                    out.close();
                }
            } catch (Exception e) {//ignore
            }
        }
    
private static voidflushIndent(int ind, java.io.BufferedWriter out)

        for (int i = 0; i < ind; i++) {
            out.write("  "); //$NON-NLS-1$
        }
    
private static voidflushPairs(java.lang.String[] attrKeys, java.lang.String[] attrValues, java.io.BufferedWriter out)

        for (int i = 0; i < attrKeys.length; i++) {
            out.write(" "); //$NON-NLS-1$
            out.write(attrKeys[i]);
            out.write("=\""); //$NON-NLS-1$
            out.write(htmlEncode(attrValues[i]));
            out.write("\""); //$NON-NLS-1$
        }
    
private static voidflushStartTag(java.lang.String tagName, java.lang.String[] attrKeys, java.lang.String[] attrValues, java.io.BufferedWriter out)

        flushIndent(++indent, out);
        out.write("<"); //$NON-NLS-1$
        out.write(tagName);
        flushPairs(attrKeys, attrValues, out);
        out.write(">"); //$NON-NLS-1$
        out.newLine();
    
private static voidflushStartTag(java.lang.String tagName, java.io.BufferedWriter out)

        flushIndent(++indent, out);
        out.write("<"); //$NON-NLS-1$
        out.write(tagName);
        out.write(">"); //$NON-NLS-1$
        out.newLine();
    
private static java.lang.StringhtmlEncode(java.lang.String s)

        StringBuffer sb = new StringBuffer();
        char c;
        for (int i = 0; i < s.length(); i++) {
            c = s.charAt(i);
            switch (c) {
            case '<":
                sb.append("<"); //$NON-NLS-1$
                break;
            case '>":
                sb.append(">"); //$NON-NLS-1$
                break;
            case '&":
                sb.append("&"); //$NON-NLS-1$
                break;
            case '\\":
                sb.append("'"); //$NON-NLS-1$
                break;
            case '"":
                sb.append("""); //$NON-NLS-1$
                break;
            default:
                sb.append(c);
            }
        }
        return sb.toString();
    
static voidimportPrefs(java.io.InputStream in)
utilities for Preferences import

        try {
            // load XML document
            Document doc = builder.parse(new InputSource(in));

            // check preferences' export version
            Element preferences;
            preferences = doc.getDocumentElement();
            String version = preferences.getAttribute("EXTERNAL_XML_VERSION"); //$NON-NLS-1$
            if (version != null && Float.parseFloat(version) > XML_VERSION) {
                // prefs.2=This preferences exported version is not supported:{0}
                throw new InvalidPreferencesFormatException(
                        Messages.getString("prefs.2", version));  //$NON-NLS-1$
            }

            // check preferences root's type
            Element root = (Element) preferences
                    .getElementsByTagName("root").item(0); //$NON-NLS-1$
            Preferences prefsRoot = null;
            String type = root.getAttribute("type"); //$NON-NLS-1$
            if (type.equals("user")) { //$NON-NLS-1$
                prefsRoot = Preferences.userRoot();
            } else {
                prefsRoot = Preferences.systemRoot();
            }

            // load node
            loadNode(prefsRoot, root);
        } catch (FactoryConfigurationError e) {
            throw new InvalidPreferencesFormatException(e);
        } catch (SAXException e) {
            throw new InvalidPreferencesFormatException(e);
        }
        // BEGIN android-removed
        // catch (TransformerException e) {
        //     throw new InvalidPreferencesFormatException(e);
        // }
        // END android-removed
    
static java.util.PropertiesloadFilePrefs(java.io.File file)
load preferences from file, if cannot load, create a new one FIXME: need lock or not?

param
file the XML file to be read
return
Properties instance which indicates the preferences key-value pairs

        return AccessController.doPrivileged(new PrivilegedAction<Properties>() {
            public Properties run() {
                return loadFilePrefsImpl(file);
            }
        });

        // try {
        // //FIXME: lines below can be deleted, because it is not required to
        // persistent at the very beginning
        // flushFilePrefs(file, result);
        // } catch (IOException e) {
        // e.printStackTrace();
        // }
    
static java.util.PropertiesloadFilePrefsImpl(java.io.File file)

        Properties result = new Properties();
        if (!file.exists()) {
            file.getParentFile().mkdirs();
        } else if (file.canRead()) {
            InputStream in = null;
            FileLock lock = null;
            try {

                FileInputStream istream = new FileInputStream(file);
                // BEGIN android-modified
                in = new BufferedInputStream(istream, 8192);
                // END android-modified
                FileChannel channel = istream.getChannel();
                lock = channel.lock(0L, Long.MAX_VALUE, true);
                Document doc = builder.parse(in);
                // BEGIN android-modified
                NodeList entries = selectNodeList(doc
                        .getDocumentElement(), "entry"); //$NON-NLS-1$
                // END android-modified
                int length = entries.getLength();
                for (int i = 0; i < length; i++) {
                    Element node = (Element) entries.item(i);
                    String key = node.getAttribute("key"); //$NON-NLS-1$
                    String value = node.getAttribute("value"); //$NON-NLS-1$
                    result.setProperty(key, value);
                }
                return result;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    lock.release();
                } catch (Exception e) {//ignore
                }
                try {
                    in.close();
                } catch (Exception e) {//ignore
                }
            }
        } else {
            file.delete();
        }
        return result;
    
private static voidloadNode(java.util.prefs.Preferences prefs, org.w3c.dom.Element node)

        // BEGIN android-note
        // removed throw clause for TransformerException
        // END android-note
        // load preferences
        // BEGIN android-changed
        NodeList children = selectNodeList(node, "node"); //$NON-NLS-1$
        NodeList entries = selectNodeList(node, "map/entry"); //$NON-NLS-1$
        // END android-changed
        int childNumber = children.getLength();
        Preferences[] prefChildren = new Preferences[childNumber];
        int entryNumber = entries.getLength();
        synchronized (((AbstractPreferences) prefs).lock) {
            if (((AbstractPreferences) prefs).isRemoved()) {
                return;
            }
            for (int i = 0; i < entryNumber; i++) {
                Element entry = (Element) entries.item(i);
                String key = entry.getAttribute("key"); //$NON-NLS-1$
                String value = entry.getAttribute("value"); //$NON-NLS-1$
                prefs.put(key, value);
            }
            // get children preferences node
            for (int i = 0; i < childNumber; i++) {
                Element child = (Element) children.item(i);
                String name = child.getAttribute("name"); //$NON-NLS-1$
                prefChildren[i] = prefs.node(name);
            }
        }

        // load children nodes after unlock
        for (int i = 0; i < childNumber; i++) {
            loadNode(prefChildren[i], (Element) children.item(i));
        }
    
private static org.w3c.dom.NodeListselectNodeList(org.w3c.dom.Element documentElement, java.lang.String string)

        
        NodeList result = null;
                
        ArrayList<Node> input = new ArrayList<Node>();
        
        String[] path = string.split("/");
        
        NodeList childNodes = documentElement.getChildNodes();
        
        if(path[0].equals("entry") || path[0].equals("node")) {
            for(int i = 0; i < childNodes.getLength(); i++) {
                Object next = childNodes.item(i);
                if(next instanceof Element) {
                    if(((Element) next).getNodeName().equals(path[0])
                            && next instanceof Node) {
                        input.add((Node)next);
                    }
                }
            }
        } else if(path[0].equals("map") && path[1].equals("entry")) {
            for(int i = 0; i < childNodes.getLength(); i++) {
                Object next = childNodes.item(i);
                if(next instanceof Element) {
                    if(((Element) next).getNodeName().equals(path[0])
                            && next instanceof Node) {
                        NodeList nextChildNodes = ((Node)next).getChildNodes();
                        for(int j = 0; j < nextChildNodes.getLength(); j++) {
                            Object subnext = nextChildNodes.item(j);
                            if(subnext instanceof Element) {
                                if(((Element)subnext).getNodeName().equals(path[1])) {
                                    input.add((Node)subnext);
                                }
                            }
                        }
                    }
                }
            }
        }
        
        result = new NodeSet(input.iterator());
        
        return result;