Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.zbus.remoting.nio.Dispatcher Maven / Gradle / Ivy
package org.zbus.remoting.nio;
import java.io.IOException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zbus.remoting.Helper;
import org.zbus.remoting.nio.Session.SessionStatus;
public class Dispatcher extends Thread {
private static final Logger log = LoggerFactory.getLogger(Dispatcher.class);
protected volatile Selector selector = null;
protected final DispatcherManager dispatcherManager;
private final Queue register = new LinkedBlockingQueue();
private final Queue unregister = new LinkedBlockingQueue();
public Dispatcher(DispatcherManager dispatcherManager, String name) throws IOException{
super(name);
this.dispatcherManager = dispatcherManager;
this.selector = Selector.open();
}
public Dispatcher(DispatcherManager dispatcherManager) throws IOException{
this(dispatcherManager, "Dispatcher");
}
public void registerChannel(SelectableChannel channel, int ops) throws IOException{
registerChannel(channel, ops, null);
}
public void registerSession(int ops, Session sess) throws IOException{
registerChannel(sess.getChannel(), ops, sess);
}
public void registerChannel(SelectableChannel channel, int ops, Session sess) throws IOException{
if(Thread.currentThread() == this){
SelectionKey key = channel.register(this.selector, ops, sess);
if(sess != null){
sess.setRegisteredKey(key);
sess.setStatus(SessionStatus.CONNECTED);
sess.getEventAdaptor().onSessionRegistered(sess);
}
} else {
this.register.offer(new Object[]{channel, ops, sess});
this.selector.wakeup();
}
}
public void unregisterSession(Session sess){
if(this.unregister.contains(sess)){
return;
}
this.unregister.add(sess);
this.selector.wakeup();
}
@Override
public void interrupt() {
super.interrupt();
try {
this.selector.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
@Override
public void run() {
try{
while(true){
selector.select();
handleRegister();
Iterator iter = selector.selectedKeys().iterator();
while(iter.hasNext()){
SelectionKey key = iter.next();
iter.remove();
if(!key.isValid()) continue;
Object att = key.attachment();
if(att != null && att instanceof Session){
((Session)att).updateLastOperationTime();
}
try{
if(key.isAcceptable()){
handleAcceptEvent(key);
} else if (key.isConnectable()){
handleConnectEvent(key);
} else if (key.isReadable()){
handleReadEvent(key);
} else if (key.isWritable()){
handleWriteEvent(key);
}
} catch(Throwable e){
disconnectWithException(key, e);
}
}
handleUnregister();
}
} catch(Throwable e) {
if(!dispatcherManager.isStarted()){
if(log.isDebugEnabled()){
log.debug(e.getMessage(), e);
}
} else {
log.error(e.getMessage(), e);
}
}
}
private void disconnectWithException(final SelectionKey key, final Throwable e){
Session sess = (Session)key.attachment();
try{
sess.setStatus(SessionStatus.ON_ERROR);
sess.getEventAdaptor().onException(e, sess);
} catch (Throwable ex){
if(!dispatcherManager.isStarted()){
log.debug(e.getMessage(), ex);
} else {
log.error(e.getMessage(), ex);
}
}
try{
if(sess != null){
sess.close();
} else {
key.channel().close();
}
key.cancel();
} catch(Throwable ex){
log.error(e.getMessage(), ex);
}
}
protected void handleRegister(){
Object[] item = null;
while( (item=this.register.poll()) != null){
try{
SelectableChannel channel = (SelectableChannel) item[0];
if (!channel.isOpen() ) continue;
int ops = (Integer)item[1];
Session sess = (Session) item[2];
SelectionKey key = channel.register(this.selector, ops, sess);
if(sess != null){
sess.setRegisteredKey(key);
sess.getEventAdaptor().onSessionRegistered(sess);
}
}catch(Exception e){
log.error(e.getMessage(), e);
}
}
}
protected void handleUnregister(){
Session sess = null;
while( (sess = this.unregister.poll()) != null ){
try {
sess.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
protected void handleAcceptEvent(SelectionKey key) throws IOException{
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel channel = server.accept();
channel.configureBlocking(false);
if(log.isDebugEnabled()){
log.debug("ACCEPT: {}=>{}", Helper.remoteAddress(channel), Helper.localAddress(channel));
}
Session sess = new Session(dispatcherManager, channel, dispatcherManager.buildEventAdaptor());
sess.setStatus(SessionStatus.CONNECTED); //set connected
sess.getEventAdaptor().onSessionAccepted(sess);
}
protected void handleConnectEvent(SelectionKey key) throws IOException{
final SocketChannel channel = (SocketChannel) key.channel();
if(log.isDebugEnabled()){
log.debug("CONNECT: {}=>{}", Helper.localAddress(channel), Helper.remoteAddress(channel));
}
Session sess = (Session) key.attachment();
if(sess == null){
throw new IOException("Session not attached yet to SelectionKey");
}
if(channel.finishConnect()){
sess.finishConnect();
}
sess.setStatus(SessionStatus.CONNECTED);
key.interestOps(0); //!!!clear interest of OP_CONNECT to avoid looping CPU !!!
sess.getEventAdaptor().onSessionConnected(sess);
}
protected void handleReadEvent(SelectionKey key) throws IOException{
Session sess = (Session) key.attachment();
if(sess == null){
throw new IOException("Session not attached yet to SelectionKey");
}
final SocketChannel channel = sess.getChannel();
if(log.isDebugEnabled()){
log.debug("READ: {}=>{}", Helper.remoteAddress(channel), Helper.localAddress(channel));
}
sess.doRead();
}
protected void handleWriteEvent(SelectionKey key) throws IOException{
Session sess = (Session) key.attachment();
if(sess == null){
throw new IOException("Session not attached yet to SelectionKey");
}
final SocketChannel channel = sess.getChannel();
if(log.isDebugEnabled()){
log.debug("WRITE: {}=>{}", Helper.remoteAddress(channel), Helper.localAddress(channel));
}
sess.doWrite();
}
}