ImmutableChannelFactory.java

package emissary.core.channels;

import org.apache.commons.lang3.Validate;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.NonWritableChannelException;
import java.nio.channels.SeekableByteChannel;

/**
 * Wrap {@link SeekableByteChannelFactory} objects to make them immutable
 */
public final class ImmutableChannelFactory {
    private ImmutableChannelFactory() {}

    /**
     * <p>
     * Wrap a provided channel factory with immutability i.e. write, truncate etc are all disabled.
     * </p>
     * 
     * <p>
     * Position *can* be changed on individual channels
     * </p>
     * 
     * @param sbcf to wrap
     * @return the wrapped channel factory
     */
    public static SeekableByteChannelFactory create(final SeekableByteChannelFactory sbcf) {
        return new ImmutableChannelFactoryImpl(sbcf);
    }

    /**
     * Wraps an existing channel factory in immutability.
     */
    private static final class ImmutableChannelFactoryImpl implements SeekableByteChannelFactory {
        /**
         * The SeekableByteChannelFactory to be made immutable.
         */
        private final SeekableByteChannelFactory sbcf;

        /**
         * Configure an immutable factory instance with the provided factory
         * 
         * @param sbcf to wrap
         */
        private ImmutableChannelFactoryImpl(final SeekableByteChannelFactory sbcf) {
            Validate.notNull(sbcf, "Required: sbcf not null");

            this.sbcf = sbcf;
        }

        /**
         * Creates an immutable channel instance upon invocation.
         * 
         * @return an immutable channel instance
         */
        @Override
        public SeekableByteChannel create() {
            return new ImmutableSeekableByteChannel(sbcf.create());
        }

    }

    /**
     * Immutable overrides for the actual implementation.
     */
    private static final class ImmutableSeekableByteChannel implements SeekableByteChannel {
        /**
         * The SeekableByteChannel to be made immutable.
         */
        private final SeekableByteChannel channel;

        private ImmutableSeekableByteChannel(final SeekableByteChannel channel) {
            Validate.notNull(channel, "Required: channel not null");
            this.channel = channel;
        }

        @Override
        public boolean isOpen() {
            return channel.isOpen();
        }

        @Override
        public void close() throws IOException {
            channel.close();
        }

        @Override
        public int read(final ByteBuffer dst) throws IOException {
            return channel.read(dst);
        }

        @Override
        public long position() throws IOException {
            return channel.position();
        }

        @Override
        public SeekableByteChannel position(final long newPosition) throws IOException {
            return channel.position(newPosition);
        }

        @Override
        public long size() throws IOException {
            return channel.size();
        }

        @Override
        public int write(final ByteBuffer src) {
            throw new NonWritableChannelException();
        }

        @Override
        public SeekableByteChannel truncate(final long size) {
            throw new NonWritableChannelException();
        }
    }
}