com.github.luohaha.worker.IoWorker Maven / Gradle / Ivy
package com.github.luohaha.worker;
import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
import com.github.luohaha.connection.Connection;
import com.github.luohaha.context.Context;
import com.github.luohaha.context.ContextBean;
import com.github.luohaha.handler.IoHandler;
import com.github.luohaha.param.Param;
public class IoWorker extends Worker implements Runnable {
private int id;
private Selector selector;
private Context context;
private IoHandler ioHandler;
private BlockingQueue jobBeans = new LinkedBlockingQueue<>();
private Logger logger = Logger.getLogger("LightComm4J");
public IoWorker(int id) {
this.id = id;
this.context = new Context();
this.selector = openSelector("[IoWorker-" + this.id + "]" + " selector open : ");
this.ioHandler = new IoHandler(this.selector, this.context);
}
@Override
public void run() {
while (true) {
try {
this.selector.select();
JobBean job = jobBeans.poll();
if (job != null) {
this.logger.fine("[IoWorker-" + this.id + "]" + " handle new job");
initSocketChannel(job);
}
Set keys = this.selector.selectedKeys();
Iterator iterator = keys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
handle(key);
iterator.remove();
}
} catch (IOException e) {
// select error
this.logger.warning("[IoWorker-" + this.id + "]" + " selector : " + e.toString());
this.selector = openSelector("[IoWorker-" + this.id + "]" + " selector open : ");
}
}
}
/**
* handle read or write event
*
* @param key
* key
* @throws IOException
* IOException
*/
private void handle(SelectionKey key) {
SocketChannel channel = (SocketChannel) key.channel();
ContextBean bean = this.context.getChanToContextBean().get(channel);
if (key.isReadable()) {
if (bean.getParam().getOnRead() == null)
return;
try {
String address = channel.getRemoteAddress().toString();
ioHandler.readDataFromRemoteSite(channel, bean.getParam().getOnRead(), bean.getParam().getOnClose());
this.logger.info("[IoWorker-" + this.id + "] read data from remote site " + address);
} catch (IOException e) {
this.logger.warning("[IoWorker-" + this.id + "] read data from remote site : " + e.toString());
if (bean.getParam().getOnReadError() != null)
bean.getParam().getOnReadError().onReadError(bean.getConnection(), e);
this.context.removeContextByChan(channel);
try {
channel.close();
} catch (IOException e1) {
// if channel already close
}
}
} else if (key.isWritable()) {
try {
String address = channel.getRemoteAddress().toString();
ioHandler.writeDataToRemoteSite(channel, bean.getParam().getOnWrite());
this.logger.info("[IoWorker-" + this.id + "] write data to remote site " + address);
} catch (IOException e) {
this.logger.warning("[IoWorker-" + this.id + "] write data to remote site : " + e.toString());
if (bean.getParam().getOnWriteError() != null)
bean.getParam().getOnWriteError().onWriteError(bean.getConnection(), e);
this.context.removeContextByChan(channel);
try {
channel.close();
} catch (IOException e1) {
// if channel already close
}
}
}
}
/**
* dispatch job to worker
*
* @param job
* job
*/
public void dispatch(JobBean job) {
this.jobBeans.add(job);
this.selector.wakeup();
}
/**
* init new job
*
* @param jobBean
* jobBean
* @throws IOException
* IOException
*/
private void initSocketChannel(JobBean jobBean) {
SocketChannel channel = jobBean.getChannel();
Param param = jobBean.getParam();
try {
channel.configureBlocking(false);
} catch (IOException e) {
// channel error
this.logger.warning("[IoWorker-" + this.id + "] channel : " + e.toString());
return;
}
int ops = 0;
if (param == null)
throw new NullPointerException();
if (param.getOnRead() != null) {
ops |= SelectionKey.OP_READ;
}
ops |= SelectionKey.OP_WRITE;
try {
channel.register(this.selector, ops);
} catch (ClosedChannelException e) {
// channel close
this.logger.warning("[IoWorker-" + this.id + "] channel : " + e.toString());
return;
}
// new connection
Connection connection = new Connection(this.context, channel, this.selector);
// init context
this.context.initContext(channel, connection, ops, param);
// call on accept or on connection
if (param.isServerParam()) {
if (param.getOnAccept() != null) {
param.getOnAccept().onAccept(connection);
}
} else {
if (param.getOnConnection() != null) {
param.getOnConnection().onConnect(connection);
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy