From f595dd749e0cc1fe7bf8176af52de4c62311d975 Mon Sep 17 00:00:00 2001 From: Michael Edgar Date: Tue, 28 Apr 2020 21:20:55 -0400 Subject: [PATCH] Add support for empty segments (no data elements) Implement release character output in writer --- .../internal/stream/StaEDIStreamWriter.java | 8 +- .../internal/stream/tokenization/Lexer.java | 18 +++- .../internal/stream/tokenization/State.java | 6 +- .../stream/StaEDIStreamWriterTest.java | 101 ++++++++++++++++++ src/test/resources/EDIFACT/pnrgov.edi | 88 +++++++++++++++ 5 files changed, 214 insertions(+), 7 deletions(-) create mode 100644 src/test/resources/EDIFACT/pnrgov.edi diff --git a/src/main/java/io/xlate/edi/internal/stream/StaEDIStreamWriter.java b/src/main/java/io/xlate/edi/internal/stream/StaEDIStreamWriter.java index 17a8e33c..aaf17c0b 100644 --- a/src/main/java/io/xlate/edi/internal/stream/StaEDIStreamWriter.java +++ b/src/main/java/io/xlate/edi/internal/stream/StaEDIStreamWriter.java @@ -495,9 +495,15 @@ public EDIStreamWriter writeElementData(CharSequence text) throws EDIStreamExcep ensureLevelAtLeast(LEVEL_ELEMENT); for (int i = 0, m = text.length(); i < m; i++) { char curr = text.charAt(i); + if (characters.isDelimiter(curr)) { - throw new IllegalArgumentException("Value contains separator"); + if (releaseIndicator > 0) { + write(releaseIndicator); + } else { + throw new IllegalArgumentException("Value contains separator: " + curr); + } } + write(curr); elementBuffer.put(curr); } diff --git a/src/main/java/io/xlate/edi/internal/stream/tokenization/Lexer.java b/src/main/java/io/xlate/edi/internal/stream/tokenization/Lexer.java index dca7ea90..69feec29 100644 --- a/src/main/java/io/xlate/edi/internal/stream/tokenization/Lexer.java +++ b/src/main/java/io/xlate/edi/internal/stream/tokenization/Lexer.java @@ -232,6 +232,10 @@ public void parse() throws IOException, EDIException { closeSegment(); eventsReady = nextEvent(); break; + case SEGMENT_EMPTY: + emptySegment(); + eventsReady = nextEvent(); + break; case COMPONENT_END: handleComponent(); eventsReady = nextEvent(); @@ -265,12 +269,12 @@ public void parse() throws IOException, EDIException { } void handleStateHeaderTag(int input) { - buffer.put((char) input); + buffer.put((char) input); dialect.appendHeader(characters, (char) input); } void handleStateElementDataBinary() { - /* + /* * Not all of the binary data has been consumed. I.e. #next was * called before completion. */ @@ -280,7 +284,7 @@ void handleStateElementDataBinary() { } void handleStateInterchangeCandidate(int input) throws EDIException { - stream.mark(500); + stream.mark(500); buffer.put((char) input); final char[] header = buffer.array(); final int length = buffer.position(); @@ -293,7 +297,7 @@ void handleStateInterchangeCandidate(int input) throws EDIException { } void handleStateHeaderData(int input) throws EDIException { - dialect.appendHeader(characters, (char) input); + dialect.appendHeader(characters, (char) input); if (characters.isDelimiter(input)) { if (characters.getDelimiter(CharacterClass.SEGMENT_DELIMITER) == input) { @@ -441,6 +445,12 @@ private void closeSegment() throws EDIException { enqueue(sen, 0); } + private void emptySegment() throws EDIException { + openSegment(); + popMode(Mode.SEGMENT); + enqueue(sen, 0); + } + private void handleElement() throws EDIException { if (previous != State.ELEMENT_END_BINARY) { addElementEvent(); diff --git a/src/main/java/io/xlate/edi/internal/stream/tokenization/State.java b/src/main/java/io/xlate/edi/internal/stream/tokenization/State.java index f4256663..7cd7268c 100644 --- a/src/main/java/io/xlate/edi/internal/stream/tokenization/State.java +++ b/src/main/java/io/xlate/edi/internal/stream/tokenization/State.java @@ -61,6 +61,7 @@ public enum State { ELEMENT_END_BINARY(17), SEGMENT_END(10), + SEGMENT_EMPTY(10), TRAILER_TAG_I(18), TRAILER_TAG_E(19), @@ -111,6 +112,7 @@ public enum State { private static final State ER = State.ELEMENT_REPEAT; private static final State EE = State.ELEMENT_END; private static final State SE = State.SEGMENT_END; + private static final State SY = State.SEGMENT_EMPTY; private static final State ZI = State.TRAILER_TAG_I; private static final State ZE = State.TRAILER_TAG_E; @@ -157,8 +159,8 @@ public enum State { /* SE+TS Tag Search */{ TS, T1, T1, T1, ZI, T1, T1, ZU, T1, T1, __, __, __, __, __, TS, __, __, __ }, /* T1 Tag Char 1 * */{ __, T2, T2, T2, T2, T2, T2, T2, T2, T2, __, __, __, __, __, __, __, __, __ }, - /* T2 Tag Char 2 * */{ __, T3, T3, T3, T3, T3, T3, T3, T3, T3, __, SB, __, __, __, __, __, __, __ }, - /* T3 Tag Char 3 * */{ __, __, __, __, __, __, __, __, __, __, __, SB, __, __, __, __, __, __, __ }, + /* T2 Tag Char 2 * */{ __, T3, T3, T3, T3, T3, T3, T3, T3, T3, SY, SB, __, __, __, __, __, __, __ }, + /* T3 Tag Char 3 * */{ __, __, __, __, __, __, __, __, __, __, SY, SB, __, __, __, __, __, __, __ }, /* Element Process */{ ED, ED, ED, ED, ED, ED, ED, ED, ED, ED, SE, EE, CE, ER, DR, EI, EI, ED, EI }, /* Data Release */{ ED, ED, ED, ED, ED, ED, ED, ED, ED, ED, ED, ED, ED, ED, ED, EI, EI, ED, EI }, diff --git a/src/test/java/io/xlate/edi/internal/stream/StaEDIStreamWriterTest.java b/src/test/java/io/xlate/edi/internal/stream/StaEDIStreamWriterTest.java index 218a3199..833e0075 100644 --- a/src/test/java/io/xlate/edi/internal/stream/StaEDIStreamWriterTest.java +++ b/src/test/java/io/xlate/edi/internal/stream/StaEDIStreamWriterTest.java @@ -631,6 +631,107 @@ public int read() throws IOException { assertEquals(expected.toString().trim(), result.toString().trim()); } + @Test + public void testInputEquivalenceEDIFACT_IATA_PNRGOV() throws Exception { + EDIInputFactory inputFactory = EDIInputFactory.newFactory(); + final ByteArrayOutputStream expected = new ByteArrayOutputStream(16384); + + InputStream source = new InputStream() { + final InputStream delegate; + { + delegate = getClass().getResourceAsStream("/EDIFACT/pnrgov.edi"); + } + + @Override + public int read() throws IOException { + int value = delegate.read(); + + if (value != -1) { + expected.write(value); + return value; + } + + return -1; + } + }; + EDIStreamReader reader = inputFactory.createEDIStreamReader(source); + + EDIOutputFactory outputFactory = EDIOutputFactory.newFactory(); + outputFactory.setProperty(EDIOutputFactory.PRETTY_PRINT, true); + ByteArrayOutputStream result = new ByteArrayOutputStream(16384); + EDIStreamWriter writer = null; + + EDIStreamEvent event; + String tag = null; + boolean composite = false; + + try { + while (reader.hasNext()) { + event = reader.next(); + + switch (event) { + case START_INTERCHANGE: + for (Map.Entry delim : reader.getDelimiters().entrySet()) { + outputFactory.setProperty(delim.getKey(), delim.getValue()); + } + writer = outputFactory.createEDIStreamWriter(result); + writer.startInterchange(); + break; + case END_INTERCHANGE: + writer.endInterchange(); + break; + case START_SEGMENT: + tag = reader.getText(); + writer.writeStartSegment(tag); + break; + case END_SEGMENT: + writer.writeEndSegment(); + break; + case START_COMPOSITE: + writer.writeStartElement(); + composite = true; + break; + case END_COMPOSITE: + writer.endElement(); + composite = false; + break; + case ELEMENT_DATA: + String text = reader.getText(); + + if ("UNA".equals(tag)) { + continue; + } + + if (composite) { + writer.startComponent(); + writer.writeElementData(text); + writer.endComponent(); + } else { + if (reader.getLocation().getElementOccurrence() > 1) { + writer.writeRepeatElement(); + } else { + writer.writeStartElement(); + } + writer.writeElementData(text); + writer.endElement(); + } + break; + case ELEMENT_DATA_BINARY: + writer.writeStartElementBinary(); + writer.writeBinaryData(reader.getBinaryData()); + writer.endElement(); + break; + default: + break; + } + } + } finally { + reader.close(); + } + + assertEquals(expected.toString().trim(), result.toString().trim()); + } + @Test public void testInputEquivalenceEDIFACTB() throws Exception { EDIInputFactory inputFactory = EDIInputFactory.newFactory(); diff --git a/src/test/resources/EDIFACT/pnrgov.edi b/src/test/resources/EDIFACT/pnrgov.edi new file mode 100644 index 00000000..2e0802e6 --- /dev/null +++ b/src/test/resources/EDIFACT/pnrgov.edi @@ -0,0 +1,88 @@ +UNA:+.\*' +UNB+IATA:1+1A+KRC+130527:0649+0003' +UNH+1+PNRGOV:11:1:IA+270513/0649/SQ/602' +MSG+:22' +ORG+1A:MUC' +TVL+270513:1430:270513:2205+SIN+ICN+SQ+602' +EQN+1' +SRC' +RCI+1A:3PGZOV::190313:1354' +DAT+700:270513:0559' +ORG+1A:MUC+32393340:SINSQ08AA+NCE+SQ:NCE+A+SG+ELPD+CFDE59+9C' +TIF+BELT:I+ISABELLE MRS:A:2:1' +FTI+SQ:8794285757' +IFT+4:63::SQ' +REF+:001C451486DFF0CC' +SSR+DOCS:HK:1:SQ:::::/P/GBR/512731999/GBR/20SEP12/FI/25OCT17/BELT/SOP HY OLIVIA/' +SSR+DOCS:HK:1:SQ:::::/P/GBR/509229987/GBR/01JUL78/F/12NOV22/BELT/ISAB ELLE RUTH/' +TIF+BELT:I+SOPHY:IN:3' +IFT+4:63::SQ' +SSR+DOCS:HK:1:SQ:::::/P/GBR/512731999/GBR/20SEP12/FI/25OCT17/BELT/SOP HY OLIVIA/' +TVL+270513:1430:270513:2205+SIN+ICN+SQ+602:D' +RPI+1+HK' +APD+333' +SSR+INFT:HK:1:SQ:::SIN:ICN:BELT/SOPHY 20SEP12+::2' +SSR+DOCS:HK:1:SQ:::SIN:ICN:/P/GBR/509229987/GBR/01JUL78/F/12NOV22/BEL T/ISABELLE RUTH/+::2' +RCI+1A:3PGZOV::190313:1354' +DAT' +ORG+SQ++++A' +TRI++SIN-168:::2' +TIF+BELT:I+ISABELLE MRS:A:2' +SSD+011D++++J' +TBD++3:33:700++HP:SIN- 168+618:0123456789:2:ICN+618:0123456788:3:ICN+618:0123456787:722356:ICN' +DAT' +ORG+SQ++++A' +TRI++SIN-169:::3' +TIF+BELT:I+SOPHY:IN:3' +SSD+011D++++J' +LTS+0/O/NM/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+0/O/SS/SQ 602 D 27MAY 1 SINICN LK1 1430 2205/NN \*1A/E\* /SQ/SG/C/I/CAB J//1///// /Y 1625/B 153//AY 1838/EY 1685/SINICN/D' +LTS+0/O/SR/SSR INFTSQNN1 BELT/SOPHY 20SEP12/SQ 602 D 27MAY SINICN/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+0/O/SR/SSR FQTVSQHK/ SQ8794285757 S/KFES/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+0/O/SR/SSR FQTSSQHK1 SQ8794285757 S/KFES/SQ 602 D 27MAY SINICN/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+0/O/SR/SSR DOCSSQHK1 P/GB/509229987/GB/01JUL78/F/12NOV22/BELT/ISABELLE//H/SQ 602 D 27MAY SINICN/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+0/Z/AMADEUS E RETAIL CR-SINSQ08AA 32393340 SU 0001AA/DS- 9CCFDE59 19MAR1354Z' +LTS+0/1/R/SR/SSR INFTSQKK1 BELT/SOPHY 20SEP12/HN/SQ 602 D 27MAY SINICN/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+1/Z/1AINV RM SQ 191354 CR-1AINV RM SQ 0000 19MAR1354Z' +LTS+2/P/QE/SINSQ0100/1C15D4' +LTS+2/Z/1AINV RM SQ 191354 CR-1AI NV R 19MAR1354Z' +LTS+3/Z/ -SQ/WSSQSAA CR-SINSQ08AA 32393340 GS 9999WS/RO-9C404C04 SAAW330SQ 00000000 19MAR1354Z' +LTS+4/Z/1AINV RM SQ 191354 CR-1AINV RM SQ +LTS+0/5/C/5/AP AMADEUS-H' +LTS+0/5/C/27/TKXL 20MAR/0004/SINSQ08AA' +LTS+5/A/27/TKOK 19MAR/SINSQ08AA' +LTS+5/6/R/27/TKOK 19MAR/SINSQ08AA' +LTS+6/Z/AA CR-SINSQ08AA 32393340 SU 0001AA/DS-9CCFDF66 19MAR1359Z' +LTS+7/Z//DCS-SYNCUS CR-SINSQ00CO 00000000 PD 6160MC/DS-9CBABA44 23MAY1240Z' +LTS+0/8/C/SR/SSR FQTVSQHK/ SQ8794285757 S/KFES/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+0/8/C/SR/SSR FQTSSQHK1 SQ8794285757 S/KFES/SQ 602 D 27MAY SINICN/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+8/A/SR/SSR FQTVSQHK/ SQ8794285757 G/QPPS/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+8/A/SR/SSR FQTSSQHK1 SQ8794285757 G/QPPS/SQ 602 D 27MAY SINICN/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+8/Z/CSXAPU CR-NCE1A0SQ0 SU 0001AA 24MAY2009Z' +LTS+9/Z/1AINV RM SQ 242009 CR-1AINV RM SQ 0000 24MAY2009Z' +LTS+1/10/R/SR/SSR INFTSQHK1 BELT/SOPHY 20SEP12/KK/SQ 602 D 27MAY SINICN/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+4/10/R/SR/SSR BSCTSQHK1/KK/SQ 602 D 27MAY SINICN/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+10/Z/ETK-ISSBOE CR-SINSQ01W0 32391122 GS 1916VV/RO-9CB39093 MUCPI2SQ1 00000000 25MAY0309Z' +LTS+11/A/SK/SK LKPX SQ HK1 Z8OWIE-P1/SQ 602 D 27MAY SINICN/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+11/Z/ISSBOE CR-SINSQ01W0 32391122 GS 1916VV/RO-9CB39093 MUCPI2SQ1 00000000 25MAY0313Z' +LTS+12/Z/MRS BELT CR-SINSQ01W0 32391122 GS 1916VV/RO-9CB39093 MUCPI2SQ1 00000000 25MAY0315Z' +LTS+13/Z/1AINV RM SQ 250315 CR-1AINV RM SQ 0000 25MAY0315Z' +LTS+14/A/7/RX \*\*\*\*\*\*\*\* ATTN SINKKXH SINKDXH SINKNXH PLS ASSIST PAX WITH TKT 618-2402058077 AND 618-2402241436 TO BE SEATED TOGETHER FLT' +LTS+14/A/7/RX SQ602 D SIN - ICN 27MAY13 14\:30 ON BSCT SEAT X MANY THANKS SINRRRSQ' +LTS+14/A/7/RX MS BELT CALLED TO UPDATE SEAT RQST X ADDED SEAT / MEAL X TELEX SENT X NIL SEATS AND MEALS X MOBILE CONTACT NUMBER UPDATED' +LTS+14/A/7/RX X VIAN / 8\:48 IST 25/5/2013' +LTS+14/Z/MRS BELT CR-SINSQ01W0 32391122 GS 1916VV/RO-9CB39093 MUCPI2SQ1 00000000 25MAY0320Z' +LTS+15/A/SR/SSR DOCSSQHK1 P/GBR/512731999/GBR/20SEP12/FI/25OCT17/BELT/SOPHY OLIVIA//BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+15/A/SR/SSR DOCSSQHK1 P/GBR/512731999/GBR/20SEP12/FI/25OCT17/BELT/SOPHY OLIVIA//SQ 602 D 27MAY SINICN/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+15/Z//DCS-IREQ CR-SINSQ00VW 00000000 GS 9743EC/DS-9CBCCB00 27MAY0422Z' +LTS+0/16/C/SR/SSR DOCSSQHK1 P/GB/509229987/GB/01JUL78/F/12NOV22/BELT/ISABELLE//H/SQ 602 D 27MAY SINICN/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+16/A/SR/SSR DOCSSQHK1 P/GBR/509229987/GBR/01JUL78/F/12NOV22/BELT/ISABELLE RUTH//SQ 602 D 27MAY SINICN/BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+16/Z//DCS-IREQ CR-SINSQ00VW 00000000 GS 9743EC/DS-9CBAB9B5 27MAY0423Z' +LTS+17/A/SR/SSR DOCSSQHK1 P/GBR/509229987/GBR/01JUL78/F/12NOV22/BELT/ISABELLE RUTH//BELT/ISABELLE MRS(ADT)(INF/SOPHY/20SEP12)' +LTS+17/Z//DCS-IREQ CR-SINSQ00VW 00000000 GS 9743EC/DS-9CBAB9D5 27MAY0423Z' +LTS+18/Z//DCS-SYNCUS CR-SINSQ00VW 00000000 GS 9743EC/DS-9CBABA1D 27MAY0423Z' +LTS+19/Z//DCS-SYNCUS CR-SINSQ00VW 00000000 GS 9743EC/DS-9CBCCB14 27MAY0423Z' +LTS+20/Z//DCS-SYNCUS CR-SINSQ00CO 00000000 PD 2092EL/DS-9CBAB94B 27MAY0559Z' +LTS+21/Z//DCS-SYNCUS CR-SINSQ00CO 00000000 PD 2092EL/DS-9CBABA1A 27MAY0559Z' +UNT+85+1' +UNZ+1+0003' \ No newline at end of file