FillChannelFactory.java

package emissary.core.channels;

import org.apache.commons.lang3.Validate;

import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.util.Arrays;

/**
 * This class creates a SeekableByteChannel of the designated size with each element having the designated value.
 */
public class FillChannelFactory {
    private FillChannelFactory() {}

    /**
     * Creates an instance of the factory with the designated size and value.
     * 
     * @param size of the SeekableByteChannel.
     * @param value of each element in the seekable byte channel.
     * @return an immutable version of the seekable byte channel with the designated value.
     */
    public static SeekableByteChannelFactory create(final long size, final byte value) {
        return SeekableByteChannelHelper.immutable(new FillChannelFactoryImpl(size, value));
    }

    /**
     * The SeekableByteChannelFactory implementation that returns a "fill" SeekableByteChannel.
     */
    private static final class FillChannelFactoryImpl implements SeekableByteChannelFactory {

        /**
         * The size of the SeekableByteChannel that is returned.
         */
        private final long size;

        /**
         * The value of each element in the SeekableByteChannel that is returned.
         */
        private final byte value;

        private FillChannelFactoryImpl(final long size, final byte value) {
            Validate.isTrue(size >= 0, "Required: size >= 0");

            this.size = size;
            this.value = value;
        }

        @Override
        public SeekableByteChannel create() {
            return new FillChannel(size, value);
        }
    }

    /**
     * The implementation of the "fill" SeekableByteChannel.
     */
    private static final class FillChannel extends AbstractSeekableByteChannel {

        /**
         * The value of each element in the SeekableByteChannel.
         */
        private final byte value;

        private final long size;

        private FillChannel(final long size, final byte value) {
            this.size = size;
            this.value = value;
        }

        @Override
        protected long sizeImpl() {
            return size;
        }

        @Override
        protected void closeImpl() {
            // Nothing to do.
        }

        @Override
        @SuppressWarnings("ByteBufferBackingArray")
        protected int readImpl(final ByteBuffer byteBuffer) {
            final int bytesToFill = byteBuffer.remaining();

            if (byteBuffer.hasArray()) {
                Arrays.fill(byteBuffer.array(), byteBuffer.position(), byteBuffer.position() + bytesToFill, value);
                byteBuffer.position(byteBuffer.position() + bytesToFill);
            } else {
                for (int i = 0; i < bytesToFill; i++) {
                    byteBuffer.put(value);
                }
            }

            return bytesToFill;
        }
    }
}