--- /dev/null 2012-12-05 14:31:23.000000000 +0000 +++ new/src/share/classes/jdk/internal/util/xml/PropertiesDefaultHandler.java 2012-12-05 14:31:23.000000000 +0000 @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.util.xml; + +import jdk.internal.util.xml.impl.XMLStreamWriter; +import jdk.internal.util.xml.impl.XMLStreamWriterImpl; +import jdk.internal.util.xml.impl.XMLStreamException; +import jdk.internal.util.xml.impl.SAXParser; +import jdk.internal.util.xml.impl.SAXParserImp; +import java.io.*; +import java.util.InvalidPropertiesFormatException; +import java.util.Iterator; +import java.util.Properties; +import java.util.Set; +import jdk.internal.org.xml.sax.Attributes; +import jdk.internal.org.xml.sax.InputSource; +import jdk.internal.org.xml.sax.SAXException; +import jdk.internal.org.xml.sax.SAXParseException; +import jdk.internal.org.xml.sax.helpers.DefaultHandler; + +/** + * A class used to aid in Properties load and save in XML. This class is + * re-implemented using a subset of SAX + * + * @author Joe Wang + * @since 8 + */ +class PropertiesDefaultHandler extends DefaultHandler { + + // Elements specified in the properties.dtd + private static final String ELEMENT_ROOT = "properties"; + private static final String ELEMENT_COMMENT = "comment"; + private static final String ELEMENT_ENTRY = "entry"; + private static final String ATTR_KEY = "key"; + // The required DTD URI for exported properties + private static final String PROPS_DTD_DECL = + ""; + private static final String PROPS_DTD_URI = + "http://java.sun.com/dtd/properties.dtd"; + private static final String PROPS_DTD = + "" + + "" + + "" + + "" + + "" + + "" + + ""; + /** + * Version number for the format of exported properties files. + */ + private static final String EXTERNAL_XML_VERSION = "1.0"; + private Properties properties; + + public void load(Properties props, InputStream in) + throws IOException, InvalidPropertiesFormatException, + UnsupportedEncodingException{ + this.properties = props; + + try { + SAXParser parser = new SAXParserImp(); + parser.parse(in, this); + } catch (SAXException saxe) { + throw new InvalidPropertiesFormatException(saxe); + } + + /** + * String xmlVersion = propertiesElement.getAttribute("version"); if + * (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0) throw new + * InvalidPropertiesFormatException( "Exported Properties 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."); + */ + } + + public void store(Properties props, OutputStream os, String comment, + String encoding) + throws IOException { + try { + XMLStreamWriter writer = new XMLStreamWriterImpl(os, encoding); + writer.writeStartDocument(); + writer.writeDTD(PROPS_DTD_DECL); + writer.writeStartElement(ELEMENT_ROOT); + if (comment != null && comment.length() > 0) { + writer.writeStartElement(ELEMENT_COMMENT); + writer.writeCharacters(comment); + writer.writeEndElement(); + } + Set keys = props.keySet(); + Iterator i = keys.iterator(); + while (i.hasNext()) { + String key = (String) i.next(); + String val = props.getProperty(key); + writer.writeStartElement(ELEMENT_ENTRY); + writer.writeAttribute(ATTR_KEY, key); + writer.writeCharacters(val); + writer.writeEndElement(); + } + writer.writeEndElement(); + writer.writeEndDocument(); + writer.close(); + } catch (XMLStreamException e) { + if (e.getCause() instanceof UnsupportedEncodingException) { + throw (UnsupportedEncodingException)e.getCause(); + } + throw new IOException(e); + } + + } + //////////////////////////////////////////////////////////////////// + // Validate while parsing + //////////////////////////////////////////////////////////////////// + final static String ALLOWED_ELEMENTS = "properties, comment, entry"; + final static String ALLOWED_COMMENT = "comment"; + //////////////////////////////////////////////////////////////////// + // Handler methods + //////////////////////////////////////////////////////////////////// + StringBuffer buf = new StringBuffer(); + boolean sawComment = false; + boolean validEntry = false; + int rootElem = 0; + String key; + String rootElm; + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if (rootElem < 2) { + rootElem++; + } + if (rootElem == 1 && !rootElm.equalsIgnoreCase(qName)) { + fatalError(new SAXParseException("Document root element \"" + qName + + "\", must match DOCTYPE root \"" + rootElm + "\"", null)); + } + if (!ALLOWED_ELEMENTS.contains(qName)) { + fatalError(new SAXParseException("Element type \"" + qName + "\" must be declared.", null)); + } + if (qName.equalsIgnoreCase(ELEMENT_ENTRY)) { + validEntry = true; + key = attributes.getValue(ATTR_KEY); + if (key == null) { + fatalError(new SAXParseException("Attribute \"key\" is required and must be specified for element type \"entry\"", null)); + } + } else if (qName.equalsIgnoreCase(ALLOWED_COMMENT)) { + if (sawComment) { + fatalError(new SAXParseException("Only one comment element may be allowed. " + + "The content of element type \"properties\" must match \"(comment?,entry*)\"", null)); + } + sawComment = true; + } + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if (validEntry) { + buf.append(ch, start, length); + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if (!ALLOWED_ELEMENTS.contains(qName)) { + fatalError(new SAXParseException("Element: " + qName + " is invalid, must match \"(comment?,entry*)\".", null)); + } + + if (validEntry) { + properties.setProperty(key, buf.toString()); + buf.delete(0, buf.length()); + validEntry = false; + } + } + + @Override + public void notationDecl(String name, String publicId, String systemId) + throws SAXException { + rootElm = name; + } + + @Override + public InputSource resolveEntity(String pubid, String sysid) + throws SAXException, IOException { + { + if (sysid.equals(PROPS_DTD_URI)) { + InputSource is; + is = new InputSource(new StringReader(PROPS_DTD)); + is.setSystemId(PROPS_DTD_URI); + return is; + } + throw new SAXException("Invalid system identifier: " + sysid); + } + } + + @Override + public void error(SAXParseException x) throws SAXException { + throw x; + } + + @Override + public void fatalError(SAXParseException x) throws SAXException { + throw x; + } + + @Override + public void warning(SAXParseException x) throws SAXException { + throw x; + } +}