/* * This file is part of muCommander, http://www.mucommander.com * Copyright (C) 2002-2016 Maxence Bernard * * muCommander is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * muCommander 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.mucommander.commons.conf; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; import javax.xml.transform.OutputKeys; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import java.io.Writer; /** * Implementation of {@link ConfigurationBuilder} used to write XML configuration streams. * <p> * Information on the XML file format can be found {@link XmlConfigurationReader here}. * </p> * @author Nicolas Rinaudo */ public class XmlConfigurationWriter implements ConfigurationBuilder { // - Class constants ----------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------- /** Factory used to create instances of {@link XmlConfigurationWriter}. */ public static final ConfigurationWriterFactory<XmlConfigurationWriter> FACTORY; // - Instance fields ----------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------- /** Writer on the destination XML stream. */ protected final ContentHandler out; /** Empty XML attributes (avoids creating a new instance on each <code>startElement</code> call). */ private final Attributes emptyAttributes = new AttributesImpl(); /** Root element name. */ protected final String rootElementName; // - Initialization ------------------------------------------------------------------------------------------------ // ----------------------------------------------------------------------------------------------------------------- static { FACTORY = new ConfigurationWriterFactory<XmlConfigurationWriter>() { public XmlConfigurationWriter getWriterInstance(Writer out) { return new XmlConfigurationWriter(out, getRootElementName()); } }; } /** * Creates a new instance of XML configuration writer. * @param out where to write the configuration data. */ protected XmlConfigurationWriter(Writer out, String rootElementName) { this.rootElementName = rootElementName; this.out = createHandler(out); } // - Writer methods ------------------------------------------------------------------------------------------------ // ----------------------------------------------------------------------------------------------------------------- private static ContentHandler createHandler(Writer out) { SAXTransformerFactory factory; TransformerHandler transformer; // Initializes the transformer factory. factory = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); factory.setAttribute("indent-number", 4); // Creates a new transformer. try {transformer = factory.newTransformerHandler();} catch(TransformerConfigurationException e) {throw new IllegalStateException(e);} // Enables indentation. transformer.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes"); // Sets the standalone property. transformer.getTransformer().setOutputProperty(OutputKeys.STANDALONE, "yes"); // Plugs the transformer into the specified stream. transformer.setResult(new StreamResult(out)); return transformer; } // - Builder methods ----------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------- protected void startElement(String name) throws ConfigurationException { try {out.startElement("", name, name, emptyAttributes);} catch(SAXException e) {throw new ConfigurationException(e);} } protected void endElement(String name) throws ConfigurationException { try {out.endElement("", name, name);} catch(SAXException e) {throw new ConfigurationException(e);} } /** * Starts a new configuration section. * @param name name of the new section. * @throws ConfigurationException as a wrapper for any <code>IOException</code> that might have occurred. */ public void startSection(String name) throws ConfigurationException { startElement(name); } /** * Ends a configuration section. * @param name name of the closed section. * @throws ConfigurationException as a wrapper for any <code>IOException</code> that might have occurred. */ public void endSection(String name) throws ConfigurationException { endElement(name); } /** * Creates a new variable in the current section. * @param name name of the new variable. * @param value value of the new variable. * @throws ConfigurationException as a wrapper for any <code>IOException</code> that might have occurred. */ public void addVariable(String name, String value) throws ConfigurationException { char[] data; try { startElement(name); data = value.toCharArray(); out.characters(data, 0, data.length); endElement(name); } catch(SAXException e) {throw new ConfigurationException(e);} } /** * Writes the XML header. * @throws ConfigurationException as a wrapper for any exception that might have occurred. */ public void startConfiguration() throws ConfigurationException { try { out.startDocument(); startElement(rootElementName); } catch(SAXException e) {throw new ConfigurationException(e);} } /** * Writes the XML footer. * @throws ConfigurationException as a wrapper for any <code>IOException</code> that might have occurred. */ public void endConfiguration() throws ConfigurationException { try { endElement(rootElementName); out.endDocument(); } catch(SAXException e) {throw new ConfigurationException(e);} } }