/* Copyright (C) 2014 konik.io * * This file is part of the Konik library. * * The Konik library is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * The Konik library 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with the Konik library. If not, see <http://www.gnu.org/licenses/>. */ package io.konik; import static java.util.logging.Level.WARNING; import static javax.xml.bind.JAXBContext.newInstance; import io.konik.exception.TransformationException; import io.konik.zugferd.Invoice; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.util.logging.Logger; import javax.inject.Named; import javax.inject.Singleton; import javax.xml.XMLConstants; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; import org.xml.sax.SAXException; /** * Transforms invoices from one representation to another. In other words marshaling and unmarshalling. * */ @Named @Singleton public class InvoiceTransformer { private static final Logger LOG = Logger.getLogger(InvoiceTransformer.class.getName()); private static final String MARSHALLING_ERROR = "Marshalling error"; private static final String KONIK_CONTEXT = "io.konik.zugferd"; private final JAXBContext jaxbContext; /** * Instantiates a default invoice transformer. */ public InvoiceTransformer() { try { this.jaxbContext = newInstance(KONIK_CONTEXT); } catch (JAXBException e) { throw new TransformationException("Could not instantiate JaxB Context", e); } } /** * Instantiates a new invoice transformer providing a JAXB Context * * @param jaxbContext the JAXB context */ InvoiceTransformer(JAXBContext jaxbContext) { this.jaxbContext = jaxbContext; } /** * Transform from XML input stream to the invoice model. * * @param xmlInputStream the xml input stream * @return the invoice model */ public Invoice toModel(InputStream xmlInputStream) { try { Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); return unmarshaller.unmarshal(new StreamSource(xmlInputStream), Invoice.class).getValue(); } catch (JAXBException e) { throw new TransformationException(MARSHALLING_ERROR, e); } } /** * Transform from XML content from File to the invoice model. * * @param file the file * @return the invoice */ @SuppressWarnings("unchecked") public Invoice toModel(File file) { try { Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); return ((JAXBElement<Invoice>) unmarshaller.unmarshal(file)).getValue(); } catch (JAXBException e) { throw new TransformationException(MARSHALLING_ERROR, e); } } /** * Transform from Invoice model to xml byte array. * * @param invoice the invoice * @return the byte[] */ public byte[] fromModel(Invoice invoice) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(16000); try { Marshaller marshaller = createMarshaller(); marshaller.marshal(invoice, outputStream); } catch (JAXBException e) { throw new TransformationException(MARSHALLING_ERROR, e); } return outputStream.toByteArray(); } /** * Transform from Invoice model to output stream. * * @param invoice the invoice * @param outputStream the output stream */ public void fromModel(Invoice invoice, OutputStream outputStream) { try { Marshaller marshaller = createMarshaller(); marshaller.marshal(invoice, outputStream); } catch (JAXBException e) { throw new TransformationException(MARSHALLING_ERROR, e); } } /** * From model Async. * * Will start a new Thread for the transformation. * * @param invoice the invoice * @param outputStream the output stream */ public void fromModelAsync(final Invoice invoice, final OutputStream outputStream) { new Thread(new Runnable() { @Override public void run() { fromModel(invoice, outputStream); try { outputStream.flush(); outputStream.close(); } catch (IOException e) { LOG.log(WARNING, "Faild to Transform Model", e); } } }).start(); } /** * Gets the ZUGFeRD schema Validator. * * @return the Schema Validator * @throws SAXException the SAX exception */ public Validator getZfSchemaValidator() throws SAXException { SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); URL schemaInvoice = InvoiceTransformer.class.getResource("/zfSchema/ZUGFeRD_1p0.xsd"); Schema invoiceSchema = sf.newSchema(schemaInvoice); return invoiceSchema.newValidator(); } private Marshaller createMarshaller() throws JAXBException { Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formatXmlOutput()); return marshaller; } protected Boolean formatXmlOutput() { return Boolean.FALSE; } }