diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java index 29cfff26..28083a13 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java @@ -1,21 +1,23 @@ -/** ********************************************************************** - * +/** + * ********************************************************************* + *

* Copyright 2018 Jochen Staerk - * + *

* Use is subject to license terms. - * + *

* 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 org.mustangproject.ZUGFeRD; import javax.xml.transform.*; @@ -36,6 +38,7 @@ public class ZUGFeRDVisualizer { FR, DE } + static final ClassLoader CLASS_LOADER = ZUGFeRDVisualizer.class.getClassLoader(); private static final String RESOURCE_PATH = ""; private static final Logger LOG = Logger.getLogger(ZUGFeRDVisualizer.class.getName()); @@ -54,6 +57,7 @@ public class ZUGFeRDVisualizer { private Templates mXsltXRTemplate = null; private Templates mXsltUBLTemplate = null; private Templates mXsltHTMLTemplate = null; + private Templates mXsltPDFTemplate = null; private Templates mXsltZF1HTMLTemplate = null; public ZUGFeRDVisualizer() { @@ -66,13 +70,19 @@ public class ZUGFeRDVisualizer { throws FileNotFoundException, TransformerException, UnsupportedEncodingException { try { - if (mXsltXRTemplate==null) { + if (mXsltXRTemplate == null) { mXsltXRTemplate = mFactory.newTemplates( new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl"))); } - mXsltHTMLTemplate = mFactory.newTemplates(new StreamSource( - CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xrechnung-html."+lang.name().toLowerCase()+".xsl"))); - if (mXsltZF1HTMLTemplate==null) { + if (mXsltPDFTemplate == null) { + mXsltPDFTemplate = mFactory.newTemplates( + new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xr-pdf.xsl"))); + } + if (mXsltHTMLTemplate == null) { + mXsltHTMLTemplate = mFactory.newTemplates(new StreamSource( + CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xrechnung-html." + lang.name().toLowerCase() + ".xsl"))); + } + if (mXsltZF1HTMLTemplate == null) { mXsltZF1HTMLTemplate = mFactory.newTemplates(new StreamSource( CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt"))); } @@ -86,14 +96,14 @@ public class ZUGFeRDVisualizer { * http://www.ferd-net.de/upload/Dokumente/FACTUR-X_ZUGFeRD_2p0_Teil1_Profil_EN16931_1p03.pdf * http://countwordsfree.com/xmlviewer */ - FileInputStream fis=new FileInputStream(xmlFilename); - String fileContent=""; + FileInputStream fis = new FileInputStream(xmlFilename); + String fileContent = ""; try { fileContent = new String(Files.readAllBytes(Paths.get(xmlFilename)), StandardCharsets.UTF_8); } catch (IOException e2) { LOG.log(Level.SEVERE, null, e2); } - + ByteArrayOutputStream iaos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -101,7 +111,7 @@ public class ZUGFeRDVisualizer { String zf2Signature = "rsm:CrossIndustryInvoice"; String ublSignature = "ubl:Invoice"; String ublCreditNoteSignature = "ubl:CreditNote"; - boolean doPostProcessing=false; + boolean doPostProcessing = false; if (fileContent.contains(zf1Signature)) { applyZF1XSLT(fis, baos); @@ -109,16 +119,16 @@ public class ZUGFeRDVisualizer { //zf2 or fx applyZF2XSLT(fis, iaos); - doPostProcessing=true; + doPostProcessing = true; } else if (fileContent.contains(ublSignature)) { //zf2 or fx applyUBL2XSLT(fis, iaos); - doPostProcessing=true; + doPostProcessing = true; } else if (fileContent.contains(ublCreditNoteSignature)) { //zf2 or fx applyUBLCreditNote2XSLT(fis, iaos); - doPostProcessing=true; + doPostProcessing = true; } if (doPostProcessing) { @@ -158,20 +168,88 @@ public class ZUGFeRDVisualizer { } } - + return baos.toString("UTF-8"); } - public void applyZF2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream) + public String toFOP(String xmlFilename) + throws FileNotFoundException, TransformerException, UnsupportedEncodingException { + + try { + if (mXsltXRTemplate == null) { + mXsltXRTemplate = mFactory.newTemplates( + new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl"))); + } + if (mXsltPDFTemplate == null) { + mXsltPDFTemplate = mFactory.newTemplates( + new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xr-pdf.xsl"))); + } + } catch (TransformerConfigurationException ex) { + LOG.log(Level.SEVERE, null, ex); + } + + FileInputStream fis = new FileInputStream(xmlFilename); + String fileContent = ""; + try { + fileContent = new String(Files.readAllBytes(Paths.get(xmlFilename)), StandardCharsets.UTF_8); + } catch (IOException e2) { + LOG.log(Level.SEVERE, null, e2); + } + + ByteArrayOutputStream iaos = new ByteArrayOutputStream(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + //zf2 or fx + applyZF2XSLT(fis, iaos); + + PipedInputStream in = new PipedInputStream(); + PipedOutputStream out; + try { + out = new PipedOutputStream(in); + new Thread(new Runnable() { + public void run() { + try { + // write the original OutputStream to the PipedOutputStream + // note that in order for the below method to work, you need + // to ensure that the data has finished writing to the + // ByteArrayOutputStream + iaos.writeTo(out); + } catch (IOException e) { + LOG.log(Level.SEVERE, null, e); + } finally { + // close the PipedOutputStream here because we're done writing data + // once this thread has completed its run + if (out != null) { + // close the PipedOutputStream cleanly + try { + out.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + LOG.log(Level.SEVERE, null, e); + } + } + } + } + }).start(); + applyXSLTToPDF(in, baos); + } catch (IOException e1) { + LOG.log(Level.SEVERE, null, e1); + } + + + return baos.toString("UTF-8"); + } + + protected void applyZF2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream) throws TransformerException { Transformer transformer = mXsltXRTemplate.newTransformer(); transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream)); } - public void applyUBL2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream) + protected void applyUBL2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream) throws TransformerException { - if (mXsltUBLTemplate==null) { + if (mXsltUBLTemplate == null) { mXsltUBLTemplate = mFactory.newTemplates( new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ubl-invoice-xr.xsl"))); } @@ -180,9 +258,9 @@ public class ZUGFeRDVisualizer { transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream)); } - public void applyUBLCreditNote2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream) + protected void applyUBLCreditNote2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream) throws TransformerException { - if (mXsltUBLTemplate==null) { + if (mXsltUBLTemplate == null) { mXsltUBLTemplate = mFactory.newTemplates( new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ubl-creditnote-xr.xsl"))); } @@ -191,20 +269,27 @@ public class ZUGFeRDVisualizer { transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream)); } - public void applyZF1XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream) + protected void applyZF1XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream) throws TransformerException { Transformer transformer = mXsltZF1HTMLTemplate.newTransformer(); transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream)); } - public void applyXSLTToHTML(final InputStream xmlFile, final OutputStream HTMLOutstream) + protected void applyXSLTToHTML(final InputStream xmlFile, final OutputStream HTMLOutstream) throws TransformerException { Transformer transformer = mXsltHTMLTemplate.newTransformer(); transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream)); } + protected void applyXSLTToPDF(final InputStream xmlFile, final OutputStream PDFOutstream) + throws TransformerException { + Transformer transformer = mXsltPDFTemplate.newTransformer(); + + transformer.transform(new StreamSource(xmlFile), new StreamResult(PDFOutstream)); + } + private static class ClasspathResourceURIResolver implements URIResolver { ClasspathResourceURIResolver() { // Do nothing, just prevents synthetic access warning. @@ -212,7 +297,7 @@ public class ZUGFeRDVisualizer { @Override public Source resolve(String href, String base) throws TransformerException { - return new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH +"stylesheets/"+ href)); + return new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/" + href)); } } } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/VisualizationTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/VisualizationTest.java index 028b39d0..94ddfdee 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/VisualizationTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/VisualizationTest.java @@ -19,17 +19,23 @@ *********************************************************************** */ package org.mustangproject.ZUGFeRD; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.Fop; +import org.apache.fop.apps.FopFactory; +import org.apache.xmlgraphics.util.MimeConstants; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; import org.mustangproject.CII.CIIToUBL; +import org.xml.sax.SAXException; -import javax.xml.transform.TransformerException; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; +import javax.xml.transform.*; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamSource; +import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Paths; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class VisualizationTest extends ResourceCase { @@ -141,4 +147,91 @@ public class VisualizationTest extends ResourceCase { // Reading ZUGFeRD assertEquals(expected, result); } + + public void testPDFVisualization() { + + // the writing part + CIIToUBL c2u = new CIIToUBL(); + String sourceFilename = "factur-x.xml"; + File CIIinputFile = getResourceAsFile(sourceFilename); + + String expected = null; + String result = null; + try { + ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer(); + /* remove file endings so that tests can also pass after checking + out from git with arbitrary options (which may include CSRF changes) + */ + result = zvi.toFOP(CIIinputFile.getAbsolutePath()); + File expectedResult=getResourceAsFile("fop.xml"); + ByteArrayOutputStream fopout = new ByteArrayOutputStream(); + //FileOutputStream outfile = new FileOutputStream("c:\\Users\\jstaerk\\temp\\fop2.pdf"); + // File out=new File("c:\\Users\\jstaerk\\temp\\fop.xml"); + +// Step 1: Construct a FopFactory by specifying a reference to the configuration file +// (reuse if you plan to render multiple documents!) + FopFactory fopFactory = FopFactory.newInstance(new File("c:\\Users\\jstaerk\\temp\\fop.xconf")); + FOUserAgent userAgent = fopFactory.newFOUserAgent(); + userAgent.getRendererOptions().put("pdf-a-mode", "PDF/A-1b"); + +// Step 2: Set up output stream. +// Note: Using BufferedOutputStream for performance reasons (helpful with FileOutputStreams). + OutputStream out = new BufferedOutputStream(new FileOutputStream(new File("c:\\Users\\jstaerk\\temp\\fop3.pdf"))); + + try { + // Step 3: Construct fop with desired output format + Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, out); + + // Step 4: Setup JAXP using identity transformer + TransformerFactory factory = TransformerFactory.newInstance(); + Transformer transformer = factory.newTransformer(); // identity transformer + + // Step 5: Setup input and output for XSLT transformation + // Setup input stream + Source src = new StreamSource(new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8))); + + // Resulting SAX events (the generated FO) must be piped through to FOP + Result res = new SAXResult(fop.getDefaultHandler()); + + // Step 6: Start XSLT transformation and FOP processing + transformer.transform(src, res); + + //Files.write(Paths.get("C:\\Users\\jstaerk\\temp\\fop.pdf"), res.toString().getBytes(StandardCharsets.UTF_8)); + + } finally { + //Clean-up + out.close(); + } + +// Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, fopout); +/* + Transformer transformer = TransformerFactory.newInstance().newTransformer( + new StreamSource(new File(args[1]))); + transformer.transform(new StreamSource(new File(args[0])), + new SAXResult(((Fop) fop).getDefaultHandler())); +*/ + // fopout.toByteArray(); + + expected = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8).replace("\r","").replace("\n",""); + // remove linebreaks as well... + + } catch (UnsupportedOperationException e) { + fail("UnsupportedOperationException should not happen: "+e.getMessage()); + } catch (IllegalArgumentException e) { + fail("IllegalArgumentException should not happen: "+e.getMessage()); + } catch (TransformerException e) { + fail("TransformerException should not happen: "+e.getMessage()); + } catch (IOException e) { + fail("IOException should not happen: "+e.getMessage()); + } catch (FOPException e) { + e.printStackTrace(); + } catch (SAXException e) { + e.printStackTrace(); + } + + assertNotNull(result); + // Reading ZUGFeRD + assertEquals(expected, result); + } + }