XMLProperties.java Source code

Java tutorial

Introduction

Here is the source code for XMLProperties.java

Source

// XMLProperties.java
// $Id: XMLProperties.java,v 1.5 2000/08/16 21:37:58 ylafon Exp $
// (c) COPYRIGHT MIT, INRIA and Keio, 1999.
// Please first read the full copyright statement in file COPYRIGHT.html

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Properties;

import org.xml.sax.AttributeList;
import org.xml.sax.DocumentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.Parser;
import org.xml.sax.SAXException;

/**
 * The <code>Properties</code> class represents a persistent set of
 * properties. The <code>Properties</code> can be saved to a stream or loaded
 * from a stream. Each key and its corresponding value in the property list is a
 * string.
 * <p>
 * A property list can contain another property list as its "defaults"; this
 * second property list is searched if the property key is not found in the
 * original property list. Because Properties inherits from Hashtable, the put
 * and putAll methods can be applied to a Properties object. Their use is
 * strongly discouraged as they allow the caller to insert entries whose keys or
 * values are not Strings. The setProperty method should be used instead. If the
 * store or save method is called on a "compromised" Properties object that
 * contains a non-String key or value, the call will fail.
 * <p>
 * This is a special implementation for XML :
 * 
 * <pre>
 *    &lt;properties&gt;
 *       &lt;key name=&quot;My_key1&quot;&gt;My_Value1&lt;/key&gt;
 *       &lt;key name=&quot;My_key2&quot;&gt;My_Value2&lt;/key&gt;
 *    &lt;/properties&gt;
 * </pre>
 * 
 * @version $Revision: 1.5 $
 * @author Philippe Le Hgaret (plh@w3.org)
 * @author Benot Mah (bmahe@w3.org)
 */
public class XMLProperties extends Properties {

    public static final String PARSER_P = "com.jclark.xml.sax.Driver";

    public boolean debug = false;

    class XMLParser implements DocumentHandler {

        final int IN_NOTHING = 0;

        final int IN_DOCUMENT = 1;

        final int IN_KEY = 2;

        int state = IN_NOTHING;

        String key;

        StringBuffer value;

        Parser parser;

        XMLParser(InputStream in) throws IOException, SAXException {
            state = IN_NOTHING;
            value = new StringBuffer();
            try {
                parser = getParser();
                parser.setDocumentHandler(this);
            } catch (Exception e) {
                e.printStackTrace();
                throw new SAXException("can't create parser ");
            }
            parser.parse(new InputSource(in));
        }

        public void startElement(String name, AttributeList atts) throws SAXException {
            if (state == IN_NOTHING) {
                if (name.equals("properties")) {
                    state = IN_DOCUMENT;
                } else {
                    throw new SAXException("attempt to find root properties");
                }
            } else if (state == IN_DOCUMENT) {
                if (name.equals("key")) {
                    state = IN_KEY;
                    key = atts.getValue("name");

                    if (key == null) {
                        throw new SAXException("no name for key " + atts);
                    }
                } else {
                    throw new SAXException("attempt to find keys");
                }
            } else {
                throw new SAXException("invalid element " + name);
            }
        }

        public void endElement(String name) throws SAXException {
            if (state == IN_KEY) {
                setProperty(key, value.toString());
                if (debug) {
                    System.out.print("<key name=\"" + key + "\">");
                    System.out.println(value.toString() + "</key>\n");
                }
                state = IN_DOCUMENT;
                name = null;
                value = new StringBuffer();
            } else if (state == IN_DOCUMENT) {
                state = IN_NOTHING;
            }
        }

        public void characters(char ch[], int start, int length) throws SAXException {
            if (state == IN_KEY) {
                compute(ch, start, length);
            }
        }

        public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
            // nothing to do
        }

        public void startDocument() throws SAXException {
            // nothing to do
        }

        public void endDocument() throws SAXException {
            // nothing to do
        }

        public void processingInstruction(String target, String data) throws SAXException {
            // nothing to do
        }

        public void setDocumentLocator(Locator locator) {
            // nothing to do
        }

        private void compute(char[] ch, int start, int length) {
            int st = start;
            int len = length - 1;
            while (st < length && ((ch[st] == '\n') || (ch[st] == '\t') || (ch[st] == ' ') || (ch[st] == '\r'))) {
                st++;
            }
            while (len > 0 && ((ch[len] == '\n') || (ch[len] == '\t') || (ch[len] == ' ') || (ch[len] == '\r'))) {
                len--;
            }

            while (st <= len) {
                value.append(ch[st]);
                st++;
            }
        }
    } // XMLParser

    private Class parser_class = null;

    /**
     * Reads a property list from an input stream.
     * 
     * @param in
     *          the input stream.
     * @exception IOException
     *              if an error occurred when reading from the input stream.
     * @since JDK1.0
     */
    public synchronized void load(InputStream in) throws IOException {
        XMLParser p = null;
        try {
            p = new XMLParser(in);
        } catch (SAXException e) {
            throw new IOException(e.getMessage());
        }
    }

    /**
     * Reads a property list from an input stream. This method try to load
     * properties with super.load() if the XMLParser failed. Use this method to
     * translate an Property set to an XML Property set.
     * 
     * @param file
     *          the properties file.
     * @exception IOException
     *              if an error occurred when reading from the input stream.
     * @since JDK1.0
     */
    public synchronized void load(File file) throws IOException {
        InputStream in = new BufferedInputStream(new FileInputStream(file));
        XMLParser p = null;
        try {
            p = new XMLParser(in);
        } catch (SAXException e) {
            try {
                in = new BufferedInputStream(new FileInputStream(file));
                super.load(in);
                in.close();
            } catch (IOException ex) {
                throw new IOException(e.getMessage());
            }
        }
    }

    /**
     * Calls the <code>store(OutputStream out, String header)</code> method and
     * suppresses IOExceptions that were thrown.
     * 
     * @deprecated This method does not throw an IOException if an I/O error
     *             occurs while saving the property list. As of JDK 1.2, the
     *             preferred way to save a properties list is via the
     *             <code>store(OutputStream out,
     * String header)</code> method.
     * 
     * @param out
     *          an output stream.
     * @param header
     *          a description of the property list.
     * @exception ClassCastException
     *              if this <code>Properties</code> object contains any keys or
     *              values that are not <code>Strings</code>.
     */
    public synchronized void save(OutputStream out, String header) {
        try {
            store(out, header);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Writes this property list (key and element pairs) in this
     * <code>Properties</code> table to the output stream in a format suitable
     * for loading into a <code>Properties</code> table using the
     * <code>load</code> method.
     * <p>
     * After the entries have been written, the output stream is flushed. The
     * output stream remains open after this method returns.
     * 
     * @param out
     *          an output stream.
     * @param header
     *          a description of the property list.
     * @exception ClassCastException
     *              if this <code>Properties</code> object contains any keys or
     *              values that are not <code>Strings</code>.
     */
    public synchronized void store(OutputStream out, String header) throws IOException {
        PrintWriter wout = new PrintWriter(out);
        wout.println("<?xml version='1.0'?>");
        if (header != null) {
            wout.println("<!--" + header + "-->");
        }

        wout.print("<properties>");
        for (Enumeration e = keys(); e.hasMoreElements();) {
            String key = (String) e.nextElement();
            String val = (String) get(key);
            wout.print("\n <key name=\"" + key + "\">");
            wout.print(encode(val));
            wout.print("</key>");
        }
        wout.print("\n</properties>");
        wout.flush();
    }

    protected StringBuffer encode(String string) {
        int len = string.length();
        StringBuffer buffer = new StringBuffer(len);
        char c;

        for (int i = 0; i < len; i++) {
            switch (c = string.charAt(i)) {
            case '&':
                buffer.append("&amp;");
                break;
            case '<':
                buffer.append("&lt;");
                break;
            case '>':
                buffer.append("&gt;");
                break;
            default:
                buffer.append(c);
            }
        }

        return buffer;
    }

    private Class getParserClass() throws ClassNotFoundException {
        if (parser_class == null)
            parser_class = Class.forName(PARSER_P);
        return parser_class;
    }

    private Parser getParser() {
        try {
            return (Parser) getParserClass().newInstance();
        } catch (Exception ex) {
            throw new RuntimeException("Unable to intantiate : " + PARSER_P);
        }
    }

    /**
     * Creates an empty property list with no default values.
     */
    public XMLProperties() {
        super();
    }

    /**
     * Creates an empty property list with the specified defaults.
     * 
     * @param defaults
     *          the defaults.
     */
    public XMLProperties(Properties defaults) {
        super(defaults);
    }

    /**
     * Creates an empty property list with the specified defaults.
     * 
     * @param parser
     *          the XML Parser classname (default is PARSER_P)
     * @param defaults
     *          the defaults.
     */
    public XMLProperties(String parser, Properties defaults) {
        super(defaults);
        try {
            parser_class = Class.forName(parser);
        } catch (ClassNotFoundException ex) {
            System.err.println("Unable to instanciate parser class: " + parser);
            System.err.println("Using default parser.");
        }
    }

    public void setDebug(boolean debug) {
        this.debug = debug;
    }

}