/** * <p> Recycles the buffer * * @param endOfLineSequence The new end of line sequence. * @param flushOutputStream The new {@code OutputStream} where to flush the data when the buffer is full. */ public void recycle(final byte[] endOfLineSequence, final OutputStream flushOutputStream){ this.circularBuffer.reset(); this.flushOutputStream = flushOutputStream; this.endOfLineSequence = endOfLineSequence; this.endOfLineSequenceMatchingLength = 0; }
boolean updateEndOfLineMatchingStatus(final byte b){ if (endOfLineSequence[endOfLineSequenceMatchingLength] == b){ endOfLineSequenceMatchingLength++; }else if (endOfLineSequence[0] == b){ endOfLineSequenceMatchingLength = 1; }else{ endOfLineSequenceMatchingLength = 0; } return isEndOfLine(); }
/** * <p> Reads all the available valid data into an {@code OutputStream} * * @param outputStream The {@code OutputStream} target of the read. * @throws IOException If the read fails. */ public void readAll(final OutputStream outputStream) throws IOException { if (isEmpty()){ return; } readChunk(outputStream, availableReadLength); }
void flushIfNeeded(){ if (flushOutputStream == null){ return; } if (circularBuffer.isFull() || isEndOfLine()) { try { if (circularBuffer.getAvailableDataLength() > 0) { if (endOfLineSequenceMatchingLength > 0) { // Need to flush a chunk int chunkSize = circularBuffer.availableReadLength - endOfLineSequenceMatchingLength; circularBuffer.readChunk(flushOutputStream, chunkSize); } else { // flush all circularBuffer.readAll(flushOutputStream); } } } catch (Exception e) { throw new IllegalStateException("Error flushing the buffer data.", e); } } if (circularBuffer.isFull()){ // Still full after flushing should never happen... throw new IllegalStateException("Unexpected error. Buffer is full after a flush."); } } }
/** * <p> Writes a byte of data in the buffer. If the buffer already encountered an end of line sequence, and exception will be thrown. * * @param data The byte of data. * @return true if the buffer encountered one of the end of line sequences, false otherwise. */ public boolean write(final byte data){ if (isEndOfLine()){ throw new IllegalStateException("Buffer is in an end of line state. You need to recycle it before writing."); } flushIfNeeded(); circularBuffer.write(data); boolean isEndOfLine = updateEndOfLineMatchingStatus(data); if (isEndOfLine){ flushIfNeeded(); } return isEndOfLine; }
/** * <p> Writes a byte in the first available slot in the buffer. If the buffer is full the oldest data written will be overwritten. * * @param data The byte to write. */ public void write(final byte data){ buffer[nextAvailablePosition] = data; nextAvailablePosition = forwards(nextAvailablePosition); if (availableReadLength > 0 && nextAvailablePosition == startValidDataIndex + 1){ // buffer is full startValidDataIndex = forwards(startValidDataIndex); } updateAvailableReadLength(true); }
void skipPreamble(final WriteContext wCtx) { int byteOfData; while ((byteOfData = wCtx.read()) != -1) { if (endOfLineBuffer.write((byte)byteOfData)) { goToState(State.IDENTIFY_PREAMBLE_DELIMITER); wCtx.setFinishedIfNoMoreData(); return; } } wCtx.setFinishedIfNoMoreData(); }
/** * <p> Constructor * * @param size The size of the buffer. Must be greater than the bigger end of line sequence * @param endOfLineSequence The end of line sequence. The {@link #write(byte)} method will return true when the end of line sequence is encountered * @param flushOutputStream The {@code OutputStream} where to flush the data when the buffer is full. If set to null the buffer can be used to skip bytes until an end of line marker. */ public EndOfLineBuffer(final int size, byte[] endOfLineSequence, final OutputStream flushOutputStream) { if (endOfLineSequence.length >= size){ throw new IllegalArgumentException("The end of line sequence cannot be larger than the buffer size. End of line sequence length: " + endOfLineSequence.length + ", buffer size: " + size); } this.circularBuffer = new CircularBuffer(size); this.flushOutputStream = flushOutputStream; this.endOfLineSequence = endOfLineSequence; this.endOfLineSequenceMatchingLength = 0; }
void getReadyForHeaders(final WriteContext wCtx) { headersByteArrayOutputStream.reset(); endOfLineBuffer.recycle(HEADER_DELIMITER, headersByteArrayOutputStream); headers = new HashMap<String, List<String>>(); goToState(State.READ_HEADERS); wCtx.setFinishedIfNoMoreData(); }
void flushIfNeeded(){ if (flushOutputStream == null){ return; } if (circularBuffer.isFull() || isEndOfLine()) { try { if (circularBuffer.getAvailableDataLength() > 0) { if (endOfLineSequenceMatchingLength > 0) { // Need to flush a chunk int chunkSize = circularBuffer.availableReadLength - endOfLineSequenceMatchingLength; circularBuffer.readChunk(flushOutputStream, chunkSize); } else { // flush all circularBuffer.readAll(flushOutputStream); } } } catch (Exception e) { throw new IllegalStateException("Error flushing the buffer data.", e); } } if (circularBuffer.isFull()){ // Still full after flushing should never happen... throw new IllegalStateException("Unexpected error. Buffer is full after a flush."); } } }
/** * <p> Writes a byte of data in the buffer. If the buffer already encountered an end of line sequence, and exception will be thrown. * * @param data The byte of data. * @return true if the buffer encountered one of the end of line sequences, false otherwise. */ public boolean write(final byte data){ if (isEndOfLine()){ throw new IllegalStateException("Buffer is in an end of line state. You need to recycle it before writing."); } flushIfNeeded(); circularBuffer.write(data); boolean isEndOfLine = updateEndOfLineMatchingStatus(data); if (isEndOfLine){ flushIfNeeded(); } return isEndOfLine; }
/** * <p> Reads all the available valid data into an {@code OutputStream} * * @param outputStream The {@code OutputStream} target of the read. * @throws IOException If the read fails. */ public void readAll(final OutputStream outputStream) throws IOException { if (isEmpty()){ return; } readChunk(outputStream, availableReadLength); }
/** * <p> Writes a byte in the first available slot in the buffer. If the buffer is full the oldest data written will be overwritten. * * @param data The byte to write. */ public void write(final byte data){ buffer[nextAvailablePosition] = data; nextAvailablePosition = forwards(nextAvailablePosition); if (availableReadLength > 0 && nextAvailablePosition == startValidDataIndex + 1){ // buffer is full startValidDataIndex = forwards(startValidDataIndex); } updateAvailableReadLength(true); }
void readBody(final WriteContext wCtx) { int byteOfData; while ((byteOfData = wCtx.read()) != -1) { if (endOfLineBuffer.write((byte)byteOfData)) { goToState(State.IDENTIFY_BODY_DELIMITER); wCtx.setFinishedIfNoMoreData(); return; } } wCtx.setFinishedIfNoMoreData(); }
/** * <p> Recycles the buffer * * @param endOfLineSequence The new end of line sequence. * @param flushOutputStream The new {@code OutputStream} where to flush the data when the buffer is full. */ public void recycle(final byte[] endOfLineSequence, final OutputStream flushOutputStream){ this.circularBuffer.reset(); this.flushOutputStream = flushOutputStream; this.endOfLineSequence = endOfLineSequence; this.endOfLineSequenceMatchingLength = 0; }
boolean updateEndOfLineMatchingStatus(final byte b){ if (endOfLineSequence[endOfLineSequenceMatchingLength] == b){ endOfLineSequenceMatchingLength++; }else if (endOfLineSequence[0] == b){ endOfLineSequenceMatchingLength = 1; }else{ endOfLineSequenceMatchingLength = 0; } return isEndOfLine(); }
/** * <p> Constructor * * @param size The size of the buffer. Must be greater than the bigger end of line sequence * @param endOfLineSequence The end of line sequence. The {@link #write(byte)} method will return true when the end of line sequence is encountered * @param flushOutputStream The {@code OutputStream} where to flush the data when the buffer is full. If set to null the buffer can be used to skip bytes until an end of line marker. */ public EndOfLineBuffer(final int size, byte[] endOfLineSequence, final OutputStream flushOutputStream) { if (endOfLineSequence.length >= size){ throw new IllegalArgumentException("The end of line sequence cannot be larger than the buffer size. End of line sequence length: " + endOfLineSequence.length + ", buffer size: " + size); } this.circularBuffer = new CircularBuffer(size); this.flushOutputStream = flushOutputStream; this.endOfLineSequence = endOfLineSequence; this.endOfLineSequenceMatchingLength = 0; }
void getReadyForHeaders(final WriteContext wCtx) { headersByteArrayOutputStream.reset(); endOfLineBuffer.recycle(HEADER_DELIMITER, headersByteArrayOutputStream); headers = new HashMap<String, List<String>>(); goToState(State.READ_HEADERS); wCtx.setFinishedIfNoMoreData(); }
void readBody(final WriteContext wCtx) { int byteOfData; while ((byteOfData = wCtx.read()) != -1) { if (endOfLineBuffer.write((byte)byteOfData)) { goToState(State.IDENTIFY_BODY_DELIMITER); wCtx.setFinishedIfNoMoreData(); return; } } wCtx.setFinishedIfNoMoreData(); }
void skipPreamble(final WriteContext wCtx) { int byteOfData; while ((byteOfData = wCtx.read()) != -1) { if (endOfLineBuffer.write((byte)byteOfData)) { goToState(State.IDENTIFY_PREAMBLE_DELIMITER); wCtx.setFinishedIfNoMoreData(); return; } } wCtx.setFinishedIfNoMoreData(); }