/* * Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package li.strolch.xmlpers.api; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.text.MessageFormat; import javanet.staxutils.IndentingXMLStreamWriter; import li.strolch.utils.exceptions.XmlException; import li.strolch.utils.helper.StringHelper; import li.strolch.utils.helper.XmlHelper; import li.strolch.xmlpers.util.DomUtil; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import javax.xml.stream.FactoryConfigurationError; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.OutputKeys; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class FileIo { public static final String DEFAULT_XML_VERSION = "1.0"; //$NON-NLS-1$ public static final String DEFAULT_ENCODING = "utf-8"; //$NON-NLS-1$ private static final Logger logger = LoggerFactory.getLogger(FileIo.class); private final File path; public FileIo(File path) { this.path = path; } public <T> void writeSax(PersistenceContext<T> ctx) { XMLStreamWriter writer = null; try { try (FileWriter fileWriter = new FileWriter(this.path);) { XMLOutputFactory factory = XMLOutputFactory.newInstance(); writer = factory.createXMLStreamWriter(fileWriter); writer = new IndentingXMLStreamWriter(writer); // start document writer.writeStartDocument(DEFAULT_ENCODING, DEFAULT_XML_VERSION); // then delegate object writing to caller SaxParser<T> saxParser = ctx.getParserFactor().getSaxParser(); saxParser.setObject(ctx.getObject()); saxParser.write(writer); // and now end writer.writeEndDocument(); writer.flush(); } } catch (FactoryConfigurationError | XMLStreamException | IOException e) { if (this.path.exists()) this.path.delete(); String msg = "Writing to file failed due to internal error: {0}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, e.getMessage()); throw new XmlException(msg, e); } if (logger.isDebugEnabled()) { String msg = "Wrote SAX to {0}"; //$NON-NLS-1$ logger.info(MessageFormat.format(msg, this.path.getAbsolutePath())); } } public <T> void readSax(PersistenceContext<T> ctx) { try { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); SaxParser<T> saxParser = ctx.getParserFactor().getSaxParser(); DefaultHandler defaultHandler = saxParser.getDefaultHandler(); sp.parse(this.path, defaultHandler); if (logger.isDebugEnabled()) { String msg = "SAX parsed file {0}"; //$NON-NLS-1$ logger.info(MessageFormat.format(msg, this.path.getAbsolutePath())); } ctx.setObject(saxParser.getObject()); } catch (ParserConfigurationException | SAXException | IOException e) { String msg = "Parsing failed due to internal error: {0}"; //$NON-NLS-1$ throw new XmlPersistenceException(MessageFormat.format(msg, e.getMessage()), e); } } public <T> void writeDom(PersistenceContext<T> ctx) { String lineSep = System.getProperty(XmlHelper.PROP_LINE_SEPARATOR); try { DomParser<T> domParser = ctx.getParserFactor().getDomParser(); domParser.setObject(ctx.getObject()); Document document = domParser.toDom(); String encoding = document.getInputEncoding(); if (encoding == null || encoding.isEmpty()) { // logger.info("No encoding passed. Using default encoding " + XmlHelper.DEFAULT_ENCODING); encoding = XmlHelper.DEFAULT_ENCODING; } if (!lineSep.equals(StringHelper.NEW_LINE)) { logger.info("Overriding line separator to \\n"); //$NON-NLS-1$ System.setProperty(XmlHelper.PROP_LINE_SEPARATOR, StringHelper.NEW_LINE); } // Set up a transformer TransformerFactory transfac = TransformerFactory.newInstance(); Transformer transformer = transfac.newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); //$NON-NLS-1$ transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ transformer.setOutputProperty(OutputKeys.ENCODING, encoding); transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2"); //$NON-NLS-1$ //$NON-NLS-2$ // transformer.setOutputProperty("{http://xml.apache.org/xalan}line-separator", "\t"); // Transform to file StreamResult result = new StreamResult(this.path); Source xmlSource = new DOMSource(document); transformer.transform(xmlSource, result); if (logger.isDebugEnabled()) { String msg = MessageFormat.format("Wrote DOM to {0}", this.path.getAbsolutePath()); //$NON-NLS-1$ logger.info(msg); } } catch (TransformerFactoryConfigurationError | TransformerException e) { if (this.path.exists()) this.path.delete(); String msg = "Writing to file failed due to internal error: {0}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, e.getMessage()); throw new XmlException(msg, e); } finally { System.setProperty(XmlHelper.PROP_LINE_SEPARATOR, lineSep); } } public <T> void readDom(PersistenceContext<T> ctx) { try { DocumentBuilder docBuilder = DomUtil.createDocumentBuilder(); Document document = docBuilder.parse(this.path); DomParser<T> domParser = ctx.getParserFactor().getDomParser(); domParser.fromDom(document); if (logger.isDebugEnabled()) { String msg = "DOM parsed file {0}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, this.path.getAbsolutePath()); logger.info(msg); } ctx.setObject(domParser.getObject()); } catch (SAXException | IOException e) { String msg = "Parsing failed due to internal error: {0}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, e.getMessage()); throw new XmlPersistenceException(msg, e); } } }