Search code examples
javabuffernio

Is hasRemaining() method really necessary while reading from the source channel of Pipe object?


The hasRemaining() method of the ByteBuffer class in java.nio package returns whether there are any elements between the current position and the limit.

At the same time, the documentation of the write() method of FileChannel class says:

An attempt is made to write up to r bytes to the channel, where r is the number of bytes remaining in the buffer, that is, src.remaining(), at the moment this method is invoked.

This is my main method where I am using a sink channel and source channel of pipes in java NIO:

try {
            Pipe pipe = Pipe.open();
            Runnable writer = () -> {
                try {
                    Pipe.SinkChannel sinkChannel = pipe.sink();
                    ByteBuffer writeBuffer = ByteBuffer.allocate(100);

                    for (int i = 0; i < 10; i++) {
                        String currentTime = "The current time is " + System.currentTimeMillis();
                        writeBuffer.put(currentTime.getBytes());
                        writeBuffer.flip();

                        while (writeBuffer.hasRemaining()) {
                            int writtenBytes = sinkChannel.write(writeBuffer);
                            System.out.println("Channel is writing " + writtenBytes + " bytes");
                        }

                        writeBuffer.flip();
                        Thread.sleep(150);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            };

            Runnable reader = () -> {
                try {
                    Pipe.SourceChannel sourceChannel = pipe.source();
                    ByteBuffer readBuffer = ByteBuffer.allocate(100);

                    for (int i = 0; i < 10; i++) {
                        int bytesRead = sourceChannel.read(readBuffer); 
                        byte[] stringRead = new byte[bytesRead];

                        readBuffer.flip();
                        readBuffer.get(stringRead);
                        readBuffer.flip();

                        System.out.println("Buffer reading '" + new String(stringRead) + "'");
                        Thread.sleep(150);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };

            new Thread(writer).start();
            new Thread(reader).start();

} catch (IOException e) {
            e.printStackTrace();
        }

I would like to know if the hasRemaining() method is really mandatory or not and when should I use it.


Solution

  • After investigating a little deeper I found that the abstract class SinkChannel that is a part of the class Pipe is implemented by a class named SinkChannelImpl.

    In the latter class, a SocketChannel object is used as a channel, and the write method is implemented in the SocketChannelImpl class since SocketChannel is an abstract class too.

    Bottom line is that when I call the write() method of the SinkChannel I am actually calling the write() method of the SocketChannelImpl class.

    Unfortunately, the documentation does not really specify if all of the remaining bytes will be written to the channel or not, quote:

    Some types of channels, depending upon their state, may write only some of the bytes or possibly none at all

    Also the code is obfuscated and will take some time to know how it works.

    So I will be using the compact() method after the write so in case some of the bytes are not written they will be moved to the beginning of the buffer.