Java tutorial
// 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> * <properties> * <key name="My_key1">My_Value1</key> * <key name="My_key2">My_Value2</key> * </properties> * </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("&"); break; case '<': buffer.append("<"); break; case '>': buffer.append(">"); 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; } }