001/* Copyright (C) 2014 konik.io 002 * 003 * This file is part of the Konik library. 004 * 005 * The Konik library is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * The Konik library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with the Konik library. If not, see <http://www.gnu.org/licenses/>. 017 */ 018package io.konik; 019 020import static javax.xml.bind.JAXBContext.newInstance; 021import io.konik.exception.TransformationException; 022import io.konik.zugferd.Invoice; 023 024import java.io.ByteArrayOutputStream; 025import java.io.File; 026import java.io.InputStream; 027import java.io.OutputStream; 028import java.net.URL; 029 030import javax.inject.Named; 031import javax.inject.Singleton; 032import javax.xml.XMLConstants; 033import javax.xml.bind.JAXBContext; 034import javax.xml.bind.JAXBElement; 035import javax.xml.bind.JAXBException; 036import javax.xml.bind.Marshaller; 037import javax.xml.bind.Unmarshaller; 038import javax.xml.transform.stream.StreamSource; 039import javax.xml.validation.Schema; 040import javax.xml.validation.SchemaFactory; 041import javax.xml.validation.Validator; 042 043import org.xml.sax.SAXException; 044 045/** 046 * Transforms invoices from one representation to another. In other words marshaling and unmarshalling. 047 * 048 */ 049@Named 050@Singleton 051public class InvoiceTransformer { 052 053 private static final String MARSHALLING_ERROR = "Marshalling error"; 054 055 private static final String KONIK_CONTEXT = "io.konik.zugferd"; 056 057 private final JAXBContext jaxbContext; 058 059 /** 060 * Instantiates a default invoice transformer. 061 */ 062 public InvoiceTransformer() { 063 try { 064 this.jaxbContext = newInstance(KONIK_CONTEXT); 065 } catch (JAXBException e) { 066 throw new TransformationException("Could not instantiate JaxB Context", e); 067 } 068 } 069 070 /** 071 * Instantiates a new invoice transformer providing a JAXB Context 072 * 073 * @param jaxbContext the JAXB context 074 */ 075 InvoiceTransformer(JAXBContext jaxbContext) { 076 this.jaxbContext = jaxbContext; 077 } 078 079 /** 080 * Transform from XML input stream to the invoice model. 081 * 082 * @param xmlInputStream the xml input stream 083 * @return the invoice model 084 */ 085 public Invoice toModel(InputStream xmlInputStream) { 086 try { 087 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 088 return unmarshaller.unmarshal(new StreamSource(xmlInputStream), Invoice.class).getValue(); 089 } catch (JAXBException e) { 090 throw new TransformationException(MARSHALLING_ERROR, e); 091 } 092 } 093 094 /** 095 * Transform from XML content from File to the invoice model. 096 * 097 * @param file the file 098 * @return the invoice 099 */ 100 @SuppressWarnings("unchecked") 101 public Invoice toModel(File file) { 102 try { 103 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 104 return ((JAXBElement<Invoice>) unmarshaller.unmarshal(file)).getValue(); 105 } catch (JAXBException e) { 106 throw new TransformationException(MARSHALLING_ERROR, e); 107 } 108 } 109 110 /** 111 * Transform from Invoice model to xml byte array. 112 * 113 * @param invoice the invoice 114 * @return the byte[] 115 */ 116 public byte[] fromModel(Invoice invoice) { 117 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(16000); 118 try { 119 Marshaller marshaller = createMarshaller(); 120 marshaller.marshal(invoice, outputStream); 121 } catch (JAXBException e) { 122 throw new TransformationException(MARSHALLING_ERROR, e); 123 } 124 return outputStream.toByteArray(); 125 } 126 127 /** 128 * Transform from Invoice model to output stream. 129 * 130 * @param invoice the invoice 131 * @param outputStream the output stream 132 */ 133 public void fromModel(Invoice invoice, OutputStream outputStream) { 134 try { 135 Marshaller marshaller = createMarshaller(); 136 marshaller.marshal(invoice, outputStream); 137 } catch (JAXBException e) { 138 throw new TransformationException(MARSHALLING_ERROR, e); 139 } 140 } 141 142 /** 143 * Gets the ZUGFeRD schema Validator. 144 * 145 * @return the Schema Validator 146 * @throws SAXException the SAX exception 147 */ 148 public Validator getZfSchemaValidator() throws SAXException { 149 SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); 150 URL schemaInvoice = InvoiceTransformer.class.getResource("/zfSchema/ZUGFeRD_1p0.xsd"); 151 Schema invoiceSchema = sf.newSchema(schemaInvoice); 152 return invoiceSchema.newValidator(); 153 } 154 155 private Marshaller createMarshaller() throws JAXBException { 156 Marshaller marshaller = jaxbContext.createMarshaller(); 157 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formatXmlOutput()); 158 return marshaller; 159 } 160 161 protected Boolean formatXmlOutput() { 162 return Boolean.FALSE; 163 } 164 165}