io.craft.atom.nio.NioByteChannel Maven / Gradle / Ivy
package io.craft.atom.nio;
import io.craft.atom.io.AbstractIoByteChannel;
import io.craft.atom.io.ChannelEvent;
import io.craft.atom.io.ChannelState;
import io.craft.atom.io.IllegalChannelStateException;
import io.craft.atom.nio.spi.NioBufferSizePredictor;
import io.craft.atom.nio.spi.NioChannelEventDispatcher;
import java.io.IOException;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.ToString;
/**
* Channel transmit bytes base nio
*
* @author mindwind
* @version 1.0, Feb 21, 2013
* @see NioTcpByteChannel
* @see NioUdpByteChannel
*/
@ToString(callSuper = true, of = { "localAddress", "remoteAddress" })
abstract public class NioByteChannel extends AbstractIoByteChannel {
protected SocketAddress localAddress ;
protected SocketAddress remoteAddress ;
protected SelectionKey selectionKey ;
protected NioProcessor processor ;
protected final Semaphore semaphore ;
protected final NioChannelEventDispatcher dispatcher ;
protected final NioBufferSizePredictor predictor ;
protected final Queue writeBufferQueue = new ConcurrentLinkedQueue() ;
protected final Queue> eventQueue = new ConcurrentLinkedQueue>();
protected final Object lock = new Object() ;
protected final AtomicBoolean scheduleFlush = new AtomicBoolean(false) ;
protected volatile boolean eventProcessing = false ;
// ~ ------------------------------------------------------------------------------------------------------------
public NioByteChannel(NioConfig config, NioBufferSizePredictor predictor, NioChannelEventDispatcher dispatcher) {
super(config.getMinReadBufferSize(), config.getDefaultReadBufferSize(), config.getMaxReadBufferSize());
this.semaphore = new Semaphore(config.getChannelEventSize(), false);
this.predictor = predictor;
this.dispatcher = dispatcher;
}
// ~ ------------------------------------------------------------------------------------------------------------
@Override
public void close() {
synchronized (lock) {
if (isClosing() || isClosed()) {
return;
}
}
processor.remove(this);
}
@Override
public boolean write(byte[] data) throws IllegalChannelStateException {
if (isClosed()) { throw new IllegalChannelStateException("Channel is closed"); }
if (isClosing()) { throw new IllegalChannelStateException("Channel is closing"); }
if (isPaused()) { throw new IllegalChannelStateException("Channel is paused"); }
if (data == null) { return false; }
setLastIoTime(System.currentTimeMillis());
getWriteBufferQueue().add(ByteBuffer.wrap(data));
processor.flush(this);
return true;
}
@Override
public Queue getWriteQueue() {
Queue q = new LinkedBlockingQueue();
for (ByteBuffer buf : writeBufferQueue) {
q.add(buf.array());
}
return q;
}
@Override
public SocketAddress getLocalAddress() {
return localAddress;
}
@Override
public SocketAddress getRemoteAddress() {
return remoteAddress;
}
public void setProcessor(NioProcessor processor) {
this.processor = processor;
}
public boolean tryAcquire() {
return semaphore.tryAcquire();
}
public void release() {
semaphore.release();
}
public int availablePermits() {
return semaphore.availablePermits();
}
public void unsetScheduleFlush() {
scheduleFlush.set(false);
}
public boolean setScheduleFlush(boolean schedule) {
if (schedule) {
return scheduleFlush.compareAndSet(false, schedule);
}
scheduleFlush.set(schedule);
return true;
}
// ~ ------------------------------------------------------------------------------------------------------------
void add(ChannelEvent event) {
eventQueue.offer(event);
}
boolean isValid() {
if (isClosing()) {
return false;
}
if (isClosed()) {
return false;
}
return true;
}
void setClosing() {
this.state = ChannelState.CLOSING;
}
void setClosed() {
this.state = ChannelState.CLOSED;
}
void setRemoteAddress(SocketAddress remoteAddress) {
this.remoteAddress = remoteAddress;
}
SelectionKey getSelectionKey() {
return selectionKey;
}
void setSelectionKey(SelectionKey key) {
this.selectionKey = key;
}
Queue getWriteBufferQueue() {
return writeBufferQueue;
}
Queue> getEventQueue() {
return eventQueue;
}
boolean isEventProcessing() {
return eventProcessing;
}
void setEventProcessing(boolean eventProcessing) {
this.eventProcessing = eventProcessing;
}
boolean isReadable() {
return isOpen() && selectionKey.isValid() && selectionKey.isReadable();
}
boolean isWritable() {
return (isOpen() || isPaused()) && selectionKey.isValid() && selectionKey.isWritable();
}
NioBufferSizePredictor getPredictor() {
return predictor;
}
// ~ ------------------------------------------------------------------------------------------------------------
protected void close0() throws IOException { /* override this */ }
protected int readTcp(ByteBuffer buf) throws IOException { return 0; /* override this */ }
protected int writeTcp(ByteBuffer buf) throws IOException { return 0; /* override this */ }
protected int writeUdp(ByteBuffer buf, SocketAddress target) throws IOException { return 0; /* override */ }
protected SocketAddress readUdp(ByteBuffer buf) throws IOException { return null; /* override this */ }
abstract protected SelectableChannel innerChannel();
}