001: package org.romaframework.wizard.schema;
002:
003: import java.io.IOException;
004: import java.io.InputStream;
005: import java.io.OutputStream;
006: import java.io.StringReader;
007: import java.util.InvalidPropertiesFormatException;
008: import java.util.Iterator;
009: import java.util.Properties;
010: import java.util.Set;
011:
012: import javax.xml.parsers.DocumentBuilder;
013: import javax.xml.parsers.DocumentBuilderFactory;
014: import javax.xml.parsers.ParserConfigurationException;
015: import javax.xml.transform.OutputKeys;
016: import javax.xml.transform.Transformer;
017: import javax.xml.transform.TransformerConfigurationException;
018: import javax.xml.transform.TransformerException;
019: import javax.xml.transform.TransformerFactory;
020: import javax.xml.transform.dom.DOMSource;
021: import javax.xml.transform.stream.StreamResult;
022:
023: import org.w3c.dom.Document;
024: import org.w3c.dom.Element;
025: import org.w3c.dom.Node;
026: import org.w3c.dom.NodeList;
027: import org.xml.sax.EntityResolver;
028: import org.xml.sax.ErrorHandler;
029: import org.xml.sax.InputSource;
030: import org.xml.sax.SAXException;
031: import org.xml.sax.SAXParseException;
032:
033: /**
034: * A class used to aid in Properties load and save in XML. Keeping this code
035: * outside of Properties helps reduce the number of classes loaded when
036: * Properties is loaded.
037: *
038: * @version 1.9, 01/23/03
039: * @author Michael McCloskey
040: * @since 1.3
041: */
042: class NoDTDXMLUtils {
043:
044: // The required DTD URI for exported properties
045: private static final String PROPS_DTD_URI = "http://www.romaframework.org/schema/properties.dtd";
046:
047: // XML loading and saving methods for Properties
048: private static final String PROPS_DTD = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
049: + "<!-- DTD for properties -->"
050: + "<!ELEMENT properties ( comment?, entry* ) >"
051: + "<!ATTLIST properties"
052: + " version CDATA #FIXED \"1.0\">"
053: + "<!ELEMENT comment (#PCDATA) >"
054: + "<!ELEMENT entry (#PCDATA) >"
055: + "<!ATTLIST entry "
056: + " key CDATA #REQUIRED>";
057: private static final String PROPS_PUBLIC = "JAVA PROPERTIES";
058: /**
059: * Version number for the format of exported properties files.
060: */
061: private static final String EXTERNAL_XML_VERSION = "1.0";
062:
063: static void load(Properties props, InputStream in)
064: throws IOException, InvalidPropertiesFormatException {
065: Document doc = null;
066: try {
067: doc = getLoadingDoc(in);
068: } catch (SAXException saxe) {
069: throw new InvalidPropertiesFormatException(saxe);
070: }
071: Element propertiesElement = (Element) doc.getChildNodes().item(
072: 1);
073: String xmlVersion = propertiesElement.getAttribute("version");
074: if (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0)
075: throw new InvalidPropertiesFormatException(
076: "Exported Properties file format version "
077: + xmlVersion
078: + " is not supported. This java installation can read"
079: + " versions "
080: + EXTERNAL_XML_VERSION
081: + " or older. You"
082: + " may need to install a newer version of JDK.");
083: importProperties(props, propertiesElement);
084: }
085:
086: static Document getLoadingDoc(InputStream in) throws SAXException,
087: IOException {
088: DocumentBuilderFactory dbf = DocumentBuilderFactory
089: .newInstance();
090: dbf.setIgnoringElementContentWhitespace(true);
091: dbf.setValidating(false);
092: dbf.setCoalescing(true);
093: dbf.setIgnoringComments(true);
094: try {
095: DocumentBuilder db = dbf.newDocumentBuilder();
096: db.setEntityResolver(new Resolver());
097: db.setErrorHandler(new EH());
098: InputSource is = new InputSource(in);
099: return db.parse(is);
100: } catch (ParserConfigurationException x) {
101: throw new Error(x);
102: }
103: }
104:
105: static void importProperties(Properties props,
106: Element propertiesElement) {
107: NodeList entries = propertiesElement.getChildNodes();
108: int numEntries = entries.getLength();
109: int start = numEntries > 0
110: && entries.item(0).getNodeName().equals("comment") ? 1
111: : 0;
112: for (int i = start; i < numEntries; i++) {
113: Element entry = (Element) entries.item(i);
114: if (entry.hasAttribute("key")) {
115: Node n = entry.getFirstChild();
116: String val = (n == null) ? "" : n.getNodeValue();
117: props.setProperty(entry.getAttribute("key"), val);
118: }
119: }
120: }
121:
122: static void save(Properties props, OutputStream os, String comment,
123: String encoding) throws IOException {
124: DocumentBuilderFactory dbf = DocumentBuilderFactory
125: .newInstance();
126: DocumentBuilder db = null;
127: try {
128: db = dbf.newDocumentBuilder();
129: } catch (ParserConfigurationException pce) {
130: assert (false);
131: }
132: Document doc = db.newDocument();
133: Element properties = (Element) doc.appendChild(doc
134: .createElement("properties"));
135:
136: if (comment != null) {
137: Element comments = (Element) properties.appendChild(doc
138: .createElement("comment"));
139: comments.appendChild(doc.createTextNode(comment));
140: }
141:
142: Set keys = props.keySet();
143: Iterator i = keys.iterator();
144: while (i.hasNext()) {
145: String key = (String) i.next();
146: Element entry = (Element) properties.appendChild(doc
147: .createElement("entry"));
148: entry.setAttribute("key", key);
149: entry.appendChild(doc
150: .createTextNode(props.getProperty(key)));
151: }
152: emitDocument(doc, os, encoding);
153: }
154:
155: static void emitDocument(Document doc, OutputStream os,
156: String encoding) throws IOException {
157: doc.setDocumentURI(PROPS_PUBLIC);
158: TransformerFactory tf = TransformerFactory.newInstance();
159: Transformer t = null;
160: try {
161: t = tf.newTransformer();
162: t
163: .setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
164: PROPS_PUBLIC);
165: t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
166: PROPS_DTD_URI);
167: t.setOutputProperty(OutputKeys.INDENT, "yes");
168: t.setOutputProperty(OutputKeys.METHOD, "xml");
169: t.setOutputProperty(OutputKeys.ENCODING, encoding);
170: } catch (TransformerConfigurationException tce) {
171: assert (false);
172: }
173: DOMSource doms = new DOMSource(doc);
174: StreamResult sr = new StreamResult(os);
175: try {
176: t.transform(doms, sr);
177: } catch (TransformerException te) {
178: IOException ioe = new IOException();
179: ioe.initCause(te);
180: throw ioe;
181: }
182: }
183:
184: private static class Resolver implements EntityResolver {
185: public InputSource resolveEntity(String pid, String sid)
186: throws SAXException {
187: // if (sid.equals(PROPS_DTD_URI)) {
188: InputSource is;
189: is = new InputSource(new StringReader(PROPS_DTD));
190: is.setSystemId(PROPS_DTD_URI);
191: is.setPublicId(PROPS_PUBLIC);
192: return is;
193: // }
194: // throw new SAXException("Invalid system identifier: " + sid);
195: }
196: }
197:
198: private static class EH implements ErrorHandler {
199: public void error(SAXParseException x) throws SAXException {
200: throw x;
201: }
202:
203: public void fatalError(SAXParseException x) throws SAXException {
204: throw x;
205: }
206:
207: public void warning(SAXParseException x) throws SAXException {
208: throw x;
209: }
210: }
211:
212: }
|