Skip to content

Commit

Permalink
Fix write binary data from ByteBuffer, use underlying stream directly (
Browse files Browse the repository at this point in the history
…#429)

Signed-off-by: Michael Edgar <michael@xlate.io>
  • Loading branch information
MikeEdgar committed Dec 31, 2023
1 parent e2e190d commit 60c8e00
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 23 deletions.
35 changes: 19 additions & 16 deletions src/main/java/io/xlate/edi/internal/stream/StaEDIStreamWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -814,12 +814,10 @@ public EDIStreamWriter writeBinaryData(InputStream binaryStream) throws EDIStrea
flush(); // Write `Writer` buffers to stream before writing binary

while ((output = binaryStream.read()) != -1) {
location.incrementOffset(output);
stream.write(output);
elementLength++;
writeBinary(output);
}
} catch (IOException e) {
throw new EDIStreamException("Exception writing binary element data", location, e);
throw new EDIStreamException("Exception reading binary data source for output", location, e);
}

return this;
Expand All @@ -831,17 +829,10 @@ public EDIStreamWriter writeBinaryData(byte[] binary, int start, int end) throws
ensureState(State.ELEMENT_DATA_BINARY);
ensureArgs(binary.length, start, end);
writeRequiredSeparators(end - start);
flush(); // Write `Writer` buffers to stream before writing binary

try {
flush(); // Write `Writer` buffers to stream before writing binary

for (int i = start; i < end; i++) {
location.incrementOffset(binary[i]);
stream.write(binary[i]);
elementLength++;
}
} catch (IOException e) {
throw new EDIStreamException("Exception writing binary element data", location, e);
for (int i = start; i < end; i++) {
writeBinary(binary[i]);
}

return this;
Expand All @@ -852,15 +843,27 @@ public EDIStreamWriter writeBinaryData(ByteBuffer binary) throws EDIStreamExcept
ensureLevel(LEVEL_ELEMENT);
ensureState(State.ELEMENT_DATA_BINARY);
writeRequiredSeparators(binary.remaining());
flush(); // Write `Writer` buffers to stream before writing binary

while (binary.hasRemaining()) {
write(binary.get());
elementLength++;
writeBinary(binary.get());
}

return this;
}

private void writeBinary(int output) throws EDIStreamException {
location.incrementOffset(output);

try {
stream.write(output);
} catch (IOException e) {
throw new EDIStreamException("Exception writing binary element data", location, e);
}

elementLength++;
}

@Override
public boolean binaryData(InputStream binary) {
// No operation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;

import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -657,7 +658,7 @@ void testWriteBinaryDataInputStream() throws EDIStreamException {
}

@Test
void testWriteBinaryDataInputStreamIOException() throws Exception {
void testWriteBinaryDataInputStreamReadIOException() throws Exception {
EDIOutputFactory factory = EDIOutputFactory.newFactory();
ByteArrayOutputStream stream = new ByteArrayOutputStream(4096);
EDIStreamWriter writer = factory.createEDIStreamWriter(stream);
Expand All @@ -672,6 +673,41 @@ void testWriteBinaryDataInputStreamIOException() throws Exception {
writer.writeElementData("4");
writer.endElement();
writer.writeStartElementBinary();
EDIStreamException thrown = assertThrows(EDIStreamException.class,
() -> writer.writeBinaryData(binaryStream));
assertEquals("Exception reading binary data source for output in segment BIN at position 2, element 2",
thrown.getMessage());
assertSame(ioException, thrown.getCause());
}

@Test
void testWriteBinaryDataInputStreamWriteIOException() throws Exception {
EDIOutputFactory factory = EDIOutputFactory.newFactory();
ByteArrayOutputStream stream = Mockito.spy(new ByteArrayOutputStream(4096));
EDIStreamWriter writer = factory.createEDIStreamWriter(stream);

byte[] binary = { '\n', 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, '\t' };
InputStream binaryStream = new ByteArrayInputStream(binary);

AtomicBoolean binaryElementStarted = new AtomicBoolean(false);
IOException ioException = new IOException();
Mockito.doAnswer(args -> {
if (binaryElementStarted.get()) {
throw ioException;
}
args.callRealMethod();
return null;
}).when(stream).write(0x00); // fail on second byte of binary stream

writer.startInterchange();
writeHeader(writer);
stream.reset();
writer.writeStartSegment("BIN");
writer.writeStartElement();
writer.writeElementData("4");
writer.endElement();
writer.writeStartElementBinary();
binaryElementStarted.set(true);
EDIStreamException thrown = assertThrows(EDIStreamException.class,
() -> writer.writeBinaryData(binaryStream));
assertEquals("Exception writing binary element data in segment BIN at position 2, element 2",
Expand All @@ -684,44 +720,44 @@ void testWriteBinaryDataByteArray() throws EDIStreamException {
EDIOutputFactory factory = EDIOutputFactory.newFactory();
ByteArrayOutputStream stream = new ByteArrayOutputStream(4096);
EDIStreamWriter writer = factory.createEDIStreamWriter(stream);
byte[] binary = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A' };
byte[] binary = { '\n', 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, '\t' };
writer.startInterchange();
writeHeader(writer);
writer.flush();
stream.reset();
writer.writeStartSegment("BIN");
writer.writeStartElement();
writer.writeElementData("11");
writer.writeElementData("8");
writer.endElement();
writer.writeStartElementBinary();
writer.writeBinaryData(binary, 0, binary.length);
writer.endElement();
writer.writeEndSegment();
writer.flush();
assertEquals("BIN*11*0123456789A~", stream.toString());
assertEquals("BIN*8*\n\u0000\u0001\u0002\u0003\u0004\u0005\t~", stream.toString());
}

@Test
void testWriteBinaryDataByteBuffer() throws EDIStreamException {
EDIOutputFactory factory = EDIOutputFactory.newFactory();
ByteArrayOutputStream stream = new ByteArrayOutputStream(4096);
EDIStreamWriter writer = factory.createEDIStreamWriter(stream);
byte[] binary = { 'B', 'U', 'S', 'T', 'M', 'Y', 'B', 'U', 'F', 'F', 'E', 'R', 'S', '\n' };
byte[] binary = { '\n', 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, '\t' };
ByteBuffer buffer = ByteBuffer.wrap(binary);
writer.startInterchange();
writeHeader(writer);
writer.flush();
stream.reset();
writer.writeStartSegment("BIN");
writer.writeStartElement();
writer.writeElementData("14");
writer.writeElementData("8");
writer.endElement();
writer.writeStartElementBinary();
writer.writeBinaryData(buffer);
writer.endElement();
writer.writeEndSegment();
writer.flush();
assertEquals("BIN*14*BUSTMYBUFFERS\n~", stream.toString());
assertEquals("BIN*8*\n\u0000\u0001\u0002\u0003\u0004\u0005\t~", stream.toString());
}

@ParameterizedTest
Expand Down

0 comments on commit 60c8e00

Please sign in to comment.