All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.athaydes.osgiaas.api.stream.LineOutputStream Maven / Gradle / Ivy

The newest version!
package com.athaydes.osgiaas.api.stream;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.function.Consumer;

/**
 * OutputStream that can be used to receive a line of text at a time from a writer.
 */
public final class LineOutputStream extends OutputStream {

    private static final int DEFAULT_BUFFER_CAPACITY = 1024;

    private final Consumer onLine;
    private final LinkedList buffers = new LinkedList<>();
    private final AutoCloseable closeWhenDone;
    private final int bufferCapacity;

    private ByteBuffer buffer;

    /**
     * Create an instance of {@link LineOutputStream} using the default buffer capacity.
     *
     * @param onLine        callback to run on each line of text received.
     * @param closeWhenDone callback to run when this stream gets closed.
     */
    public LineOutputStream( Consumer onLine, AutoCloseable closeWhenDone ) {
        this( onLine, closeWhenDone, DEFAULT_BUFFER_CAPACITY );
    }

    /**
     * Create an instance of {@link LineOutputStream}.
     *
     * @param onLine         callback to run on each line of text received.
     * @param closeWhenDone  callback to run when this stream gets closed.
     * @param bufferCapacity internal buffer capacity.
     *                       If the given capacity is not enough, new buffers are created as needed.
     */
    public LineOutputStream( Consumer onLine,
                             AutoCloseable closeWhenDone,
                             int bufferCapacity ) {
        this.onLine = onLine;
        this.closeWhenDone = closeWhenDone;
        this.bufferCapacity = bufferCapacity;

        if ( bufferCapacity < 1 ) {
            throw new IllegalArgumentException( "bufferCapacity must be greater than 0" );
        }

        startNewByteBuffer();
    }

    private void startNewByteBuffer() {
        buffer = ByteBuffer.allocate( bufferCapacity );
        buffers.add( buffer );
    }

    private String readBuffers() {
        int totalSize = 0;
        for (int i = 0; i < buffers.size() - 1; i++) {
            totalSize += bufferCapacity;
        }

        totalSize += buffers.getLast().position();

        byte[] finalArray = new byte[ totalSize ];

        // unload all full ByteBuffers into the final array
        int currentFirstIndex = 0;
        while ( buffers.size() > 1 ) {
            ByteBuffer currentBuffer = buffers.removeFirst();
            currentBuffer.rewind();
            currentBuffer.get( finalArray, currentFirstIndex, bufferCapacity );
            currentFirstIndex += bufferCapacity;
        }

        // unload the last ByteBuffer now (do not remove it as there must be always one buffer at least)
        buffer = buffers.getFirst();
        int bufferPosition = buffer.position();
        buffer.rewind();
        buffer.get( finalArray, currentFirstIndex, bufferPosition );
        buffer.rewind();

        return new String( finalArray, StandardCharsets.UTF_8 );
    }

    @Override
    public void write( int b ) throws IOException {
        if ( b == '\n' ) {
            consumeLine();
            return;
        }

        if ( buffer.position() >= bufferCapacity ) {
            startNewByteBuffer();
        }

        // as specified by the write() docs, we just throw away the 24 high-order bits
        buffer.put( ( byte ) b );
    }

    private void consumeLine() {
        if ( buffers.size() > 1 || buffer.position() > 0 ) {
            onLine.accept( readBuffers() );
        }
    }

    @Override
    public void close() throws IOException {
        consumeLine();
        buffers.clear();
        try {
            closeWhenDone.close();
        } catch ( Exception e ) {
            throw new IOException( e );
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy