/*
* Copyright 2005-2015 by BerryWorks Software, LLC. All rights reserved.
*/
package com.berryworks.edireader.util;
import com.berryworks.edireader.DefaultXMLTags;
import com.berryworks.edireader.EDIReaderFactory;
import com.berryworks.edireader.EDISyntaxException;
import com.berryworks.edireader.benchmark.EDITestData;
import com.berryworks.edireader.demo.EDISplitter;
import com.berryworks.edireader.splitter.ClosingDetails;
import com.berryworks.edireader.splitter.HandlerFactory;
import com.berryworks.edireader.splitter.SplittingHandler;
import com.berryworks.edireader.util.dom.DocumentUtil;
import com.berryworks.edireader.util.sax.SAXObjectHandler;
import com.berryworks.edireader.util.sax.SAXObjectReader;
import org.custommonkey.xmlunit.Diff;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXSource;
import java.io.*;
import static org.junit.Assert.*;
public class SplitterTest extends VerboseTestCase {
private Reader inputReader;
@Test
public void testOneInterchangeOneDocument() throws Exception {
inputReader = new StringReader(EDITestData.getAnsiInterchange());
MyHandlerFactory factory = new MyHandlerFactory();
new SplittingHandler(factory).split(new InputSource(inputReader));
assertEquals(1, factory.getCreateCalls());
assertEquals(332, factory.getSAXEventsWritten());
assertEquals(1, factory.getInterchangeCount());
assertEquals(1, factory.getGroupCount());
assertEquals(1, factory.getTransactionCount());
factory.getReaderThread().join();
assertEquals(331, factory.getSAXEventsRead());
}
@Test
public void testOneInterchangeTwoGroupsOneDocumentEach() throws Exception {
inputReader = new StringReader(EDITestData.getAnsiInterchange(2, 1));
MyHandlerFactory factory = new MyHandlerFactory();
new SplittingHandler(factory).split(new InputSource(inputReader));
assertEquals(2, factory.getCreateCalls());
assertEquals(664, factory.getSAXEventsWritten());
assertEquals(2, factory.getInterchangeCount());
assertEquals(2, factory.getGroupCount());
assertEquals(2, factory.getTransactionCount());
factory.getReaderThread().join();
assertEquals(662, factory.getSAXEventsRead());
}
@Test
public void testOneInterchangeOneDocumentIntoDOM() throws Exception {
inputReader = new StringReader(EDITestData.getAnsiInterchange());
MyDomHandlerFactory factory = new MyDomHandlerFactory();
new SplittingHandler(factory).split(new InputSource(inputReader));
assertEquals(1, factory.getCreateCalls());
assertEquals(332, factory.getSAXEventsWritten());
factory.shutdown();
Document controlDom = generateDOM(EDITestData.getAnsiInputSource());
Diff diff = new Diff(controlDom, factory.getDom());
boolean identical = diff.identical();
if (!identical) {
fail(diff.toString());
}
}
private Document generateDOM(InputSource inputSource) throws IOException, EDISyntaxException, TransformerException {
XMLReader ediReader = EDIReaderFactory.createEDIReader(inputSource);
SAXSource source = new SAXSource(ediReader, inputSource);
DOMResult domResult = new DOMResult();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(source, domResult);
return (Document) domResult.getNode();
}
@Test
public void testTwoInterchangeOneDocumentEach() throws Exception {
String ansiInterchange = EDITestData.getAnsiInterchange();
ansiInterchange = ansiInterchange + ansiInterchange;
inputReader = new StringReader(ansiInterchange);
MyHandlerFactory factory = new MyHandlerFactory();
new SplittingHandler(factory).split(new InputSource(inputReader));
assertEquals(2, factory.getCreateCalls());
assertEquals(664, factory.getSAXEventsWritten());
factory.getReaderThread().join();
assertEquals(662, factory.getSAXEventsRead());
assertEquals(2, factory.getInterchangeCount());
assertEquals(2, factory.getGroupCount());
assertEquals(2, factory.getTransactionCount());
}
@Test
public void testTwoInterchangeTwoDocumentsEach() throws Exception {
String ansiInterchange = EDITestData.getAnsiInterchange(2);
ansiInterchange = ansiInterchange + ansiInterchange;
MyHandlerFactory factory = new MyHandlerFactory();
new SplittingHandler(factory).split(new InputSource(new StringReader(ansiInterchange)));
assertEquals(4, factory.getCreateCalls());
assertEquals(1328, factory.getSAXEventsWritten());
factory.getReaderThread().join();
assertEquals(1324, factory.getSAXEventsRead());
assertEquals(4, factory.getInterchangeCount());
assertEquals(4, factory.getGroupCount());
assertEquals(4, factory.getTransactionCount());
}
@Test
public void testTwoInterchangeTwoDocumentsEachIntoDOMs() throws Exception {
String ansiInterchange = EDITestData.getAnsiInterchange(2);
ansiInterchange = ansiInterchange + ansiInterchange;
inputReader = new StringReader(ansiInterchange);
MyDomHandlerFactory factory = new MyDomHandlerFactory();
new SplittingHandler(factory).split(new InputSource(inputReader));
assertEquals(4, factory.getCreateCalls());
assertEquals(1328, factory.getSAXEventsWritten());
factory.shutdown();
Document controlDom = generateDOM(EDITestData.getAnsiInputSource());
Diff diff = new Diff(controlDom, factory.getDom());
boolean identical = diff.identical();
if (!identical) {
fail(diff.toString());
}
}
@Test
public void testMain() throws Exception {
PrintStream systemOut = System.out;
final ByteArrayOutputStream redirectedOut = new ByteArrayOutputStream();
System.setOut(new PrintStream(redirectedOut));
FileUtil.stringToFile(EDITestData.getAnsiInterchange(2), "toSplit.edi");
String args[] = new String[]{"toSplit.edi", "-o", getTestresultsPath() + "x12/split-0000.xml"};
EDISplitter.main(args);
System.setOut(systemOut);
assertEquals("\nEDI input parsed into 2 XML output files\n", redirectedOut.toString());
assertEquals(2, EDISplitter.getCount());
File file = new File(getTestresultsPath() + "x12/split-0002.xml");
assertNotNull(file);
assertTrue(file.exists());
InputSource inputSource = new InputSource(new FileReader(file));
DocumentUtil util = DocumentUtil.getInstance();
Document dom = util.buildDocumentFromXml(inputSource);
assertNotNull(dom);
Element element = DocumentUtil.position(dom.getDocumentElement(), new String[]{"interchange"});
String controlAttribute = element.getAttribute("Control");
assertEquals("000038449", controlAttribute);
element = DocumentUtil.position(element, new String[]{"sender", "address"});
String qualAttribute = element.getAttribute("Qual");
assertEquals("ZZ", qualAttribute);
}
class MyHandlerFactory implements HandlerFactory {
private int createCalls;
private SAXObjectHandler handler;
private InputStream pipedInputStream;
private Runnable readerRunnable;
private Thread readerThread;
private int interchangeCount, groupCount, transactionCount;
public MyHandlerFactory() {
try {
OutputStream pipedOutputStream = new PipedOutputStream();
pipedInputStream = new PipedInputStream((PipedOutputStream) pipedOutputStream);
// outputStream = new FileOutputStream("queue.ser");
handler = new SAXObjectHandler(pipedOutputStream);
readerRunnable = createRunnable(pipedInputStream);
readerThread = new Thread(readerRunnable);
readerThread.start();
} catch (IOException e) {
throw new RuntimeException("Unable to construct SAXObjectHandler", e);
}
}
protected Runnable createRunnable(InputStream stream) {
return new MyReaderThread(this, stream);
}
@Override
public void markEndOfStream() throws IOException {
handler.markEndOfStream();
}
@Override
public ContentHandler createDocument() {
createCalls++;
return handler;
}
@Override
public void closeDocument(ClosingDetails closingDetails) throws IOException {
}
public int getCreateCalls() {
return createCalls;
}
public int getSAXEventsWritten() {
return handler.getSAXEventsWritten();
}
public int getSAXEventsRead() {
return ((MyReaderThread) readerRunnable).getSAXEventsWritten();
}
public Thread getReaderThread() {
return readerThread;
}
public void close() throws IOException {
System.err.println("closing pipedInputStream");
pipedInputStream.close();
}
public int getInterchangeCount() {
return interchangeCount;
}
public void incrementInterchangeCount() {
interchangeCount++;
}
public int getGroupCount() {
return groupCount;
}
public void incrementGroupCount() {
groupCount++;
}
public int getTransactionCount() {
return transactionCount;
}
public void incrementTransactionCount() {
transactionCount++;
}
}
class MyDomHandlerFactory extends MyHandlerFactory {
private MyTransformThread transformThread;
protected Runnable createRunnable(InputStream stream) {
transformThread = new MyTransformThread(this, stream);
return transformThread;
}
public Document getDom() {
return transformThread.getDom();
}
public void shutdown() throws InterruptedException {
transformThread.shutdown();
getReaderThread().join();
}
}
class MyReaderThread implements Runnable {
protected final XMLReader reader;
protected final InputSource inputSource;
protected final InputStream inputStream;
private MyHandler finalHandler;
public MyReaderThread(MyHandlerFactory handlerFactory, InputStream inputStream) {
reader = new SAXObjectReader();
finalHandler = new MyHandler(handlerFactory);
reader.setContentHandler(finalHandler);
this.inputStream = inputStream;
inputSource = new InputSource(inputStream);
}
public void run() {
try {
while (true)
reader.parse(inputSource);
} catch (EOFException ignored) {
} catch (IOException | SAXException e) {
System.err.println(getClass().getName() + " caught " + e);
}
if (verbose) trace(getClass().getName() + " run() complete");
}
public int getSAXEventsWritten() {
return finalHandler.getSAXEventsRead();
}
}
class MyTransformThread extends MyReaderThread {
private Document document;
private volatile boolean shutdown = false;
public MyTransformThread(MyHandlerFactory factory, InputStream inputStream) {
super(factory, inputStream);
}
public void run() {
try {
while (!shutdown) {
if (verbose) trace("available in transformer input stream: " + inputStream.available());
DOMResult domResult = new DOMResult();
SAXSource source = new SAXSource(reader, inputSource);
if (verbose) trace("calling transform");
TransformerFactory.newInstance().newTransformer().transform(source, domResult);
if (verbose) trace("return from transform");
if (document == null)
document = (Document) domResult.getNode();
}
} catch (Exception e) {
if (verbose) trace(getClass().getName() + " caught " + e);
if (verbose) trace(getClass().getName() + " run() complete");
}
}
public Document getDom() {
return document;
}
public void shutdown() {
shutdown = true;
}
}
class MyHandler extends DefaultHandler {
private int documentCount;
private int elementCount;
private int attributeCount;
private int charCount;
private int sAXEventsRead;
private final MyHandlerFactory handlerFactory;
public MyHandler(MyHandlerFactory handlerFactory) {
this.handlerFactory = handlerFactory;
}
public void startDocument() throws SAXException {
documentCount++;
sAXEventsRead++;
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
elementCount++;
attributeCount += attributes.getLength();
sAXEventsRead++;
if (DefaultXMLTags.getInstance().getInterchangeTag().equals(qName)) {
handlerFactory.incrementInterchangeCount();
} else if (DefaultXMLTags.getInstance().getGroupTag().equals(qName)) {
handlerFactory.incrementGroupCount();
} else if (DefaultXMLTags.getInstance().getDocumentTag().equals(qName)) {
handlerFactory.incrementTransactionCount();
}
}
public void endElement(String uri, String localName, String qName) throws SAXException {
sAXEventsRead++;
}
public void characters(char ch[], int start, int length) throws SAXException {
charCount += length;
sAXEventsRead++;
}
public int getSAXEventsRead() {
return sAXEventsRead;
}
}
}