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

org.zodiac.sdk.nio.channeling.ChannelRunner Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version
package org.zodiac.sdk.nio.channeling;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Queue;
import java.util.function.Predicate;

class ChannelRunner extends AbstractChannelRunner {

    private final SocketChannel sc;
    private Object context;
    private final Queue forRunners;
    private Predicate currentPredicate = null;
    private ChannelingTask predicateTask;
    private ChannelingTask ioTask;
    private ByteBuffer readBuffer, currWritingBuffer;
    SocketAddress remoteAddress;
    Then then;
    ErrorCallback errorCallback = null;
    private long actionTime;
    private int lastProcessedBytes;

    static final Then DEFAULT_CALLBACK = sc -> {
        /** Do nothing **/
    };

    static final ErrorCallback DEFAULT_ERRORCALLBACK = (sc, e) -> e.printStackTrace();
    private boolean isEagerRead, removeEagerReadSignal;

    /**
     * 
     * @param sc socket channel
     * @param context context
     * @param bufferSize buffer size
     * @param channelRunners channel runners queue
     */
    ChannelRunner(SocketChannel sc, Object context, int bufferSize,
                  Queue channelRunners) {
        this.sc = sc;
        this.context = context;
        this.readBuffer = ByteBuffer.allocate(bufferSize);
        this.forRunners = channelRunners;
        this.isEagerRead = false;
        this.removeEagerReadSignal = false;
        this.lastProcessedBytes = 0;
//        this.actionTime = 0;
        try {
            sc.configureBlocking(false);
//            sc.socket().setKeepAlive(true);
//            sc.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @Override
    public Object getContext() {
        return context;
    }

    @Override
    public void setContext(Object context) {
        this.context = context;
    }

    @Override
    public SocketChannel getSocketChannel() {
        return sc;
    }

    @Override
    public long getActionTime() {
        return actionTime;
    }

    @Override
    public int getLastProcessedBytes() {
        return lastProcessedBytes;
    }

    @Override
    public void noEagerRead() {
        this.removeEagerReadSignal = true;
    }

    @Override
    public boolean isEagerRead() {
        return isEagerRead;
    }

    @Override
    public void setLastProcessedBytes(int lastProcessedBytes) {
        this.lastProcessedBytes = lastProcessedBytes;
    }

    @Override
    public void setPredicateTask(Predicate predicateTask) {
        this.currentPredicate = predicateTask;
    }

    @Override
    public void setIoTask(ChannelingTask nextIoTask) {
//        if(ioTask == DO_REMOVE_EAGER_READ)
//        switch (nextIoTask) {
//
//            case DO_CONNECT:
//            case DO_EAGER_READ:
//                break;
//            case DO_READ:
//
//
//                break;
//            case DO_WRITE:
//                ioTask = DO_REMOVE_EAGER_READ_FROM_WRITE;
//                break;
//            case DO_CLOSE:
//                ioTask = DO_REMOVE_EAGER_READ_FROM_CLOSE;
//                break;
//            case DO_IDLE:
//                break;
//            case DO_REMOVE_EAGER_READ_FROM_READ:
//                break;
//            case :
//                break;
//            case DO_REMOVE_EAGER_READ_FROM_IDLE:
//                break;
//        }

        this.ioTask = nextIoTask;
    }

    @Override
    public boolean tryRemoveEagerRead() {
        if(removeEagerReadSignal && isEagerRead) {
            isEagerRead = false;
            removeEagerReadSignal = false;
            // Return true to remove successfully
            return true;
        }

        return false;
    }

    @Override
    public boolean isSSL() {
        return false;
    }

    @Override
    public ChannelingSocket withConnect(SocketAddress remote) {
        then = DEFAULT_CALLBACK;
        if (errorCallback == null) {
            errorCallback = DEFAULT_ERRORCALLBACK;
        }
        this.remoteAddress = remote;
        this.setIoTask(ChannelingTask.DO_CONNECT);

        return this;
    }

    @Override
    public ChannelingSocket withConnect(String host, int port) {
        return withConnect(new InetSocketAddress(host, port));
    }

    private ChannelingSocket withRead(boolean eager) {
        return withRead(-1, eager);
    }

    private ChannelingSocket withRead(int length, boolean eager) {
        then = DEFAULT_CALLBACK;
        if (errorCallback == null) {
            errorCallback = DEFAULT_ERRORCALLBACK;
        }
        // set to 0 position to reread everything
        if (length > readBuffer.capacity()) {
            readBuffer = increaseCapacity(readBuffer, length);
        }
        readBuffer.clear();
        if (length >= 0) {
            readBuffer.limit(length);
        }
        this.isEagerRead = eager;
        this.setIoTask(ChannelingTask.DO_READ);
        return this;
    }

    private ChannelingSocket withRead(ByteBuffer readBuffer, boolean eager) {
        then = DEFAULT_CALLBACK;
        if (errorCallback == null) {
            errorCallback = DEFAULT_ERRORCALLBACK;
        }
        this.readBuffer = readBuffer;
        this.isEagerRead = eager;
        this.setIoTask(ChannelingTask.DO_READ);
        return this;
    }

    @Override
    public ChannelingSocket withRead() {
        return withRead(-1, false);
    }

    @Override
    public ChannelingSocket withRead(int length) {
        return withRead(length, false);
    }

    @Override
    public ChannelingSocket withRead(ByteBuffer readBuffer) {
        return withRead(readBuffer, false);
    }

    @Override
    public ChannelingSocket withEagerRead() {
        return withRead(-1, true);
    }

    @Override
    public ChannelingSocket withEagerRead(int length) {
        return withRead(length, true);
    }

    @Override
    public ChannelingSocket withEagerRead(ByteBuffer readBuffer) {
        return withRead(readBuffer, true);
    }


    @Override
    public ChannelingSocket withWrite(ByteBuffer byteBuffer) {
        then = DEFAULT_CALLBACK;
        if (errorCallback == null) {
            errorCallback = DEFAULT_ERRORCALLBACK;
        }
        // Change back to flip mode, later channeling need to READ from buffer and write to server side
        this.currWritingBuffer = byteBuffer;
        this.setIoTask(ChannelingTask.DO_WRITE);
        return this;
    }

    @Override
    public ChannelingSocket withClose() {
        then = DEFAULT_CALLBACK;
        if (errorCallback == null) {
            errorCallback = DEFAULT_ERRORCALLBACK;
        }
        this.setIoTask(ChannelingTask.DO_CLOSE);

        return this;
    }

    @Override
    public void connect(SocketAddress remote, Then then) {
        withConnect(remote).then(then);
    }

    @Override
    public void connect(String host, int port, Then then) {
        withConnect(host, port).then(then);
    }

    @Override
    public void connect(SocketAddress remote, WhenConnectingStatus when, Then then) {
        withConnect(remote).when(when).then(then);
    }

    @Override
    public void connect(String host, int port, WhenConnectingStatus when, Then then) {
        withConnect(host, port).when(when).then(then);
    }

    @Override
    public void read(Then then) {
        withRead().then(then);
    }

    @Override
    public void read(WhenChannelingSocket when, Then then) {
        withRead().when(when).then(then);
    }

    @Override
    public void read(int length, Then then) {
        withRead(length).then(then);
    }

    @Override
    public void read(int length, WhenChannelingSocket when, Then then) {
        withRead(length).when(when).then(then);
    }

    @Override
    public void read(ByteBuffer readBufferHolder, Then then) {
        withRead(readBufferHolder).then(then);
    }

    @Override
    public void read(ByteBuffer readBufferHolder, WhenChannelingSocket when, Then then) {
        withRead(readBufferHolder).when(when).then(then);
    }

    @Override
    public void write(ByteBuffer messageBuffer, Then then) {
        withWrite(messageBuffer).then(then);
    }

    @Override
    public void write(ByteBuffer messageBuffer, WhenChannelingSocket when, Then then) {
        withWrite(messageBuffer).when(when).then(then);
    }

    @Override
    public void close(Then then) {
        withClose().then(then);
    }

    @Override
    public void close(WhenChannelingSocket when, Then then) {
        withClose().when(when).then(then);
    }

    @Override
    public void connect(SocketAddress remote, Then then, ErrorCallback errorCallback) {
        withConnect(remote).then(then, errorCallback);
    }

    @Override
    public void connect(String host, int port, Then then, ErrorCallback errorCallback) {
        withConnect(host, port).then(then, errorCallback);
    }

    @Override
    public void connect(SocketAddress remote, WhenConnectingStatus when, Then then, ErrorCallback errorCallback) {
        withConnect(remote).when(when).then(then, errorCallback);
    }

    @Override
    public void connect(String host, int port, WhenConnectingStatus when, Then then, ErrorCallback errorCallback) {
        withConnect(host, port).when(when).then(then, errorCallback);
    }

    @Override
    public void read(Then then, ErrorCallback errorCallback) {
        withRead().then(then, errorCallback);
    }

    @Override
    public void read(WhenChannelingSocket when, Then then, ErrorCallback errorCallback) {
        withRead().when(when).then(then, errorCallback);
    }

    @Override
    public void read(int length, Then then, ErrorCallback errorCallback) {
        withRead(length).then(then, errorCallback);
    }

    @Override
    public void read(int length, WhenChannelingSocket when, Then then, ErrorCallback errorCallback) {
        withRead(length).when(when).then(then, errorCallback);
    }

    @Override
    public void read(ByteBuffer readBufferHolder, Then then, ErrorCallback errorCallback) {
        withRead(readBufferHolder).then(then, errorCallback);
    }

    @Override
    public void read(ByteBuffer readBufferHolder, WhenChannelingSocket when, Then then, ErrorCallback errorCallback) {
        withRead(readBufferHolder).when(when).then(then, errorCallback);
    }

    @Override
    public void write(ByteBuffer messageBuffer, Then then, ErrorCallback errorCallback) {
        withWrite(messageBuffer).then(then, errorCallback);
    }

    @Override
    public void write(ByteBuffer messageBuffer, WhenChannelingSocket when, Then then, ErrorCallback errorCallback) {
        withWrite(messageBuffer).when(when).then(then, errorCallback);
    }

    @Override
    public void close(Then then, ErrorCallback errorCallback) {
        withClose().then(then, errorCallback);
    }

    @Override
    public void close(WhenChannelingSocket when, Then then, ErrorCallback errorCallback) {
        withClose().when(when).then(then, errorCallback);
    }

    @Override
    public ChannelingSocket when(WhenReadingByteBuffer whenPredicate) {
        predicateTask = ChannelingTask.WHEN_READ_BYTEBUFFER;
        currentPredicate = whenPredicate;
        return this;
    }

    @Override
    public ChannelingSocket when(WhenWritingByteBuffer whenPredicate) {
        predicateTask = ChannelingTask.WHEN_WRITE_BYTEBUFFER;
        currentPredicate = whenPredicate;
        return this;
    }


    @Override
    public ChannelingSocket when(WhenSocketChannel whenPredicate) {
        predicateTask = ChannelingTask.WHEN_SOCKETCHANNEL;
        currentPredicate = whenPredicate;
        return this;
    }


    @Override
    public ChannelingSocket when(WhenChannelingSocket whenPredicate) {
        predicateTask = ChannelingTask.WHEN_CHANNELING_SOCKET;
        currentPredicate = whenPredicate;
        return this;
    }

    @Override
    public ChannelingSocket when(WhenConnectingStatus whenPredicate) {
        predicateTask = ChannelingTask.WHEN_CONNECT_STATUS;
        currentPredicate = whenPredicate;
        return this;
    }

    @Override
    public ChannelingSocket when(WhenReadWriteProcess whenPredicate) {
        predicateTask = ChannelingTask.WHEN_READWRITE_PROCESS;
        currentPredicate = whenPredicate;
        return this;
    }

    @Override
    public ChannelingSocket when(WhenClosingStatus whenPredicate) {
        predicateTask = ChannelingTask.WHEN_CLOSING_PROCESS;
        currentPredicate = whenPredicate;
        return this;
    }

    @Override
    public void then(Then $then, ErrorCallback $errorCallback) {
        then = $then;
        errorCallback = $errorCallback;
        triggerEvent();
    }

    private void triggerEvent() {
        actionTime = new Date().getTime();
        forRunners.offer(this);
    }

    // Inherit super error call back
    @Override
    public void then(Then then$) {
        then(then$, errorCallback != null ? errorCallback : DEFAULT_ERRORCALLBACK);
    }

    @Override
    public Predicate getCurrentPredicate() {
        return currentPredicate;
    }

    @Override
    public ChannelingTask getPredicateTask() {
        return predicateTask;
    }

    @Override
    public ChannelingTask getIoTask() {
        return ioTask;
    }

    @Override
    public ByteBuffer getReadBuffer() {
        return readBuffer;
    }

    @Override
    public SocketAddress getRemoteAddress() {
        return remoteAddress;
    }

    @Override
    public ByteBuffer getCurrWritingBuffer() {
        return currWritingBuffer;
    }

    @Override
    public Then getThen() {
        return then;
    }

    @Override
    public ErrorCallback getErrorCallBack() {
        return errorCallback;
    }

    protected static ByteBuffer doubleTheBuffer(ByteBuffer buffer) {
        return increaseCapacity(buffer, buffer.capacity() * 2);
    }


    /**
     * ref http://www.java2s.com/example/java/java.nio/increase-bytebuffers-capacity.html
     * Increase ByteBuffer's capacity.
     *
     * @param buffer the ByteBuffer want to increase capacity
     * @param size   increased size
     * @return increased capacity ByteBuffer
     * @throws IllegalArgumentException if size less than 0 or buffer is null
     */
    public static ByteBuffer increaseCapacity(ByteBuffer buffer, int size)
            throws IllegalArgumentException {
        if (buffer == null)
            throw new IllegalArgumentException("buffer is null");
        if (size < 0)
            throw new IllegalArgumentException("size less than 0");

        int capacity = buffer.capacity() + size;
        ByteBuffer result = allocate(capacity, buffer.isDirect());
        buffer.flip();
        result.put(buffer);
        return result;
    }

    /**
     * Allocate ByteBuffer.
     *
     * @param capacity ByteBuffer capacity
     * @param direct   allocate DirectByteBuffer
     * @return allocated ByteBuffer
     * @throws IllegalArgumentException if capacity is negative
     */
    public static ByteBuffer allocate(int capacity, boolean direct)
            throws IllegalArgumentException {
        if (capacity < 0)
            throw new IllegalArgumentException("capacity can't be negative");
        return direct ? ByteBuffer.allocateDirect(capacity) : ByteBuffer
                .allocate(capacity);
    }


    private static int checkHowmuchBytesStillCanWriteToBuffer(ByteBuffer byteBuffer) {
        // change to flip(reading mode) to check how much capacity left
        byteBuffer.flip();

        int leftOverSpace = (byteBuffer.capacity() - byteBuffer.limit());

        // Done and change to write mode, continue to write
        byteBuffer.compact();

        return leftOverSpace;
    }

    private static int checkHowmuchBytesStillCanReadFromBuffer(ByteBuffer byteBuffer) {
        // change to flip(reading mode) to check how much can read
        byteBuffer.flip();

        int bytesCanRead = byteBuffer.limit() - byteBuffer.position();

        return bytesCanRead;
    }

    @Override
    public int getSSLMinimumInputBufferSize() {
        throw new IllegalStateException("SSL is not support for this socket");
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy