diff --git a/src/main/java/io/xlate/edi/internal/stream/tokenization/Dialect.java b/src/main/java/io/xlate/edi/internal/stream/tokenization/Dialect.java index cdf11e68..5cdae9c5 100644 --- a/src/main/java/io/xlate/edi/internal/stream/tokenization/Dialect.java +++ b/src/main/java/io/xlate/edi/internal/stream/tokenization/Dialect.java @@ -31,7 +31,7 @@ public abstract class Dialect { protected char elementRepeater; protected boolean initialized; - protected boolean rejected; + protected String rejectionMessage; protected String transactionType; protected String transactionVersionString; @@ -90,7 +90,11 @@ public boolean isConfirmed() { } public boolean isRejected() { - return rejected; + return rejectionMessage != null; + } + + public String getRejectionMessage() { + return rejectionMessage; } /** diff --git a/src/main/java/io/xlate/edi/internal/stream/tokenization/EDIFACTDialect.java b/src/main/java/io/xlate/edi/internal/stream/tokenization/EDIFACTDialect.java index 472cc0c8..cb04d0e0 100644 --- a/src/main/java/io/xlate/edi/internal/stream/tokenization/EDIFACTDialect.java +++ b/src/main/java/io/xlate/edi/internal/stream/tokenization/EDIFACTDialect.java @@ -100,6 +100,7 @@ boolean initialize(CharacterSet characters) { characters.setClass(segmentDelimiter, CharacterClass.SEGMENT_DELIMITER); initialized = true; } else { + rejectionMessage = "Unable to obtain version from EDIFACT header segment"; initialized = false; } @@ -189,7 +190,7 @@ boolean processInterchangeHeader(CharacterSet characters, char value) { */ characters.setClass(elementDelimiter, CharacterClass.ELEMENT_DELIMITER); } else if (segmentDelimiter == value) { - rejected = !initialize(characters); + initialize(characters); return isConfirmed(); } @@ -232,7 +233,7 @@ boolean processServiceStringAdvice(CharacterSet characters, char value) { header.deleteCharAt(index--); } else if (isIndexBeyondUNBFirstElement()) { if (value == elementDelimiter || value == segmentDelimiter) { - rejected = !initialize(characters); + initialize(characters); proceed = isConfirmed(); } } else if (value == 'B') { 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 07e2aa7a..c0f2b808 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 @@ -185,7 +185,7 @@ public void parse() throws IOException, EDIException { CharacterClass clazz = characters.getClass(input); previous = state; state = State.transition(state, dialect, clazz); - LOGGER.finer(() -> String.format("State %s(%s, %s) -> %s", previous, clazz, Dialect.getStandard(dialect), state)); + LOGGER.finer(() -> String.format("%s + (%s, '%s', %s) -> %s", previous, Dialect.getStandard(dialect), (char) input, clazz, state)); switch (state) { case INITIAL: @@ -418,9 +418,10 @@ private boolean dialectConfirmed(State confirmed) throws EDIException { } else if (dialect.isRejected()) { buffer.clear(); clearQueues(); + String rejectionMessage = dialect.getRejectionMessage(); dialect = null; state = State.INITIAL; - throw error(EDIException.INVALID_STATE, "Invalid header segment"); + throw error(EDIException.INVALID_STATE, rejectionMessage); } return false; diff --git a/src/main/java/io/xlate/edi/internal/stream/tokenization/TradacomsDialect.java b/src/main/java/io/xlate/edi/internal/stream/tokenization/TradacomsDialect.java index a064c8c0..b8ce9bad 100644 --- a/src/main/java/io/xlate/edi/internal/stream/tokenization/TradacomsDialect.java +++ b/src/main/java/io/xlate/edi/internal/stream/tokenization/TradacomsDialect.java @@ -24,6 +24,7 @@ public class TradacomsDialect extends Dialect { public static final String MHD = "MHD"; private static final String[] EMPTY = new String[0]; + private static final int TRADACOMS_ELEMENT_OFFSET = 3; static final char DFLT_SEGMENT_TERMINATOR = '\''; static final char DFLT_DATA_ELEMENT_SEPARATOR = '+'; @@ -62,6 +63,7 @@ boolean initialize(CharacterSet characters) { initialized = true; characters.setClass(segmentDelimiter, CharacterClass.SEGMENT_DELIMITER); } else { + rejectionMessage = "Unable to obtain version from TRADACOMS header segment"; initialized = false; } @@ -97,7 +99,11 @@ public boolean appendHeader(CharacterSet characters, char value) { case 0: header = new StringBuilder(); break; - case 3: + case TRADACOMS_ELEMENT_OFFSET: + if (value != segmentTagTerminator) { + rejectionMessage = String.format("Expected TRADACOMS segment tag delimiter '%s', but found '%s'", segmentTagTerminator, value); + return false; + } /* * TRADACOMS delimiters are fixed. Do not set the element delimiter * until after the segment tag has been passed to prevent triggering @@ -124,7 +130,7 @@ public boolean appendHeader(CharacterSet characters, char value) { boolean processInterchangeHeader(CharacterSet characters, char value) { if (segmentDelimiter == value) { - rejected = !initialize(characters); + initialize(characters); return isConfirmed(); } diff --git a/src/main/java/io/xlate/edi/internal/stream/tokenization/X12Dialect.java b/src/main/java/io/xlate/edi/internal/stream/tokenization/X12Dialect.java index cb1dc574..66025aa7 100644 --- a/src/main/java/io/xlate/edi/internal/stream/tokenization/X12Dialect.java +++ b/src/main/java/io/xlate/edi/internal/stream/tokenization/X12Dialect.java @@ -80,6 +80,7 @@ boolean initialize(CharacterSet characters) { for (int i = 0, m = X12_ISA_LENGTH; i < m; i++) { if (ELEMENT == header[i] && X12_ISA_TOKENS[e++] != i) { + rejectionMessage = String.format("Unexpected element delimiter value '%s' in X12 header position %d", ELEMENT, i + 1); return false; } } @@ -150,7 +151,7 @@ public boolean appendHeader(CharacterSet characters, char value) { boolean proceed = true; if (index == X12_SEGMENT_OFFSET) { - rejected = !initialize(characters); + initialize(characters); proceed = isConfirmed(); } diff --git a/src/test/java/io/xlate/edi/internal/stream/StaEDIStreamReaderTest.java b/src/test/java/io/xlate/edi/internal/stream/StaEDIStreamReaderTest.java index 218687bf..86c043ba 100644 --- a/src/test/java/io/xlate/edi/internal/stream/StaEDIStreamReaderTest.java +++ b/src/test/java/io/xlate/edi/internal/stream/StaEDIStreamReaderTest.java @@ -1939,4 +1939,47 @@ void testDecimalScaleAvailableFromSchema() throws EDISchemaException, IOExceptio assertEquals(new BigDecimal("2554.38"), tds01); } + + /** + * Original issue: https://github.com/xlate/staedi/issues/174 + * + * @throws Exception + */ + @Test + void testOtherDialectTerminalSegmentsIgnored_Issue174() throws Exception { + EDIInputFactory factory = EDIInputFactory.newFactory(); + factory.setProperty(EDIInputFactory.EDI_VALIDATE_CONTROL_STRUCTURE, true); + factory.setProperty(EDIInputFactory.EDI_VALIDATE_CONTROL_CODE_VALUES, false); + EDIStreamReader reader = factory.createEDIStreamReader(getClass().getResourceAsStream("/EDIFACT/issue174/other_dialect_term_segments.edi")); + List unexpected = new ArrayList<>(); + + try { + while (reader.hasNext()) { + switch (reader.next()) { + case SEGMENT_ERROR: + case ELEMENT_OCCURRENCE_ERROR: + case ELEMENT_DATA_ERROR: + unexpected.add(reader.getErrorType()); + break; + default: + break; + } + } + } catch (Exception e) { + unexpected.add(e); + } finally { + reader.close(); + } + + assertEquals(0, unexpected.size()); + } + + @Test + void testTRADACOMS_IncorrectSegmentTagDelimiterIsInvalid() throws Exception { + EDIInputFactory factory = EDIInputFactory.newFactory(); + EDIStreamReader reader = factory.createEDIStreamReader(getClass().getResourceAsStream("/TRADACOMS/order-wrong-segment-tag-delimiter.edi")); + List unexpected = new ArrayList<>(); + EDIStreamException thrown = assertThrows(EDIStreamException.class, () -> reader.next()); + assertTrue(thrown.getMessage().contains("Expected TRADACOMS segment tag delimiter")); + } } diff --git a/src/test/resources/EDIFACT/issue174/other_dialect_term_segments.edi b/src/test/resources/EDIFACT/issue174/other_dialect_term_segments.edi new file mode 100644 index 00000000..f3ea5489 --- /dev/null +++ b/src/test/resources/EDIFACT/issue174/other_dialect_term_segments.edi @@ -0,0 +1,6 @@ +UNB+UNOA:3+005435656:1+006415160:1+210220:1605+00000000000001' +UNH+00000000000001+CUSTOM:D:97B:UN' +IEA+1:525' +END+1:525' +UNT+24+00000000000001' +UNZ+1+00000000000001' diff --git a/src/test/resources/TRADACOMS/order-wrong-segment-tag-delimiter.edi b/src/test/resources/TRADACOMS/order-wrong-segment-tag-delimiter.edi new file mode 100644 index 00000000..56a119aa --- /dev/null +++ b/src/test/resources/TRADACOMS/order-wrong-segment-tag-delimiter.edi @@ -0,0 +1,18 @@ +STX+ANA:1+5000000000000:SOME STORES LTD+5010000000000:SUPPLIER UK LTD+070315:130233+000007+PASSW+ORDHDR+B' +MHD+1+ORDHDR:9' +TYP+0430+NEW-ORDERS' +SDT+5010000000000:000030034' +CDT+5000000000000' +FIL+1630+1+070315' +MTR+6' +MHD+2+ORDERS:9' +CLO+5000000000283:89828+EAST SOMEWHERE DEPOT' +ORD+70970::070315' +DIN+070321++0000' +OLD+1+5010210000000++:00893592+12+60++++CRUSTY ROLLS:4 PACK' +OTR+1' +MTR+7' +MHD+3+ORDTLR:9' +OFT+1' +MTR+3' +END+3'