/**
* (c) 2011-2012 tkuri
*/
package tkuri.jxy.server;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;
import tkuri.jxy.Const;
import tkuri.jxy.Util;
import tkuri.jxy.arch.ASelectionAttachment;
import tkuri.jxy.arch.ChannelReader;
import tkuri.jxy.arch.TheSelector;
/**
* ClientPeer
*/
public class ClientPeer extends ASelectionAttachment {
static int ID = 0;
private int id_ = ID++;
private SelectionKey selKey_ = null;
SocketChannel socket = null;
ChannelReader reader = null;
ClientRequest request = null;
private ITransfer ascent_ = null;
private LinkedList<ITransfer> descentQ_ = new LinkedList<ITransfer>();
private ITransfer descent_ = null;
/**
* ctor
*
* @param aSock
*/
public ClientPeer(SocketChannel aSock) throws Exception {
socket = aSock;
reader = new ChannelReader(aSock);
socket.configureBlocking(false);
selKey_ = TheSelector.registerChannel(
socket,
SelectionKey.OP_READ,
this);
}
@Override
public int interestOps() {
if (selKey_.isValid()) {
return selKey_.interestOps();
} else {
return 0;
}
}
@Override
public void interestOps(int aOps) {
if (selKey_.isValid()) {
selKey_.interestOps(aOps);
}
}
@Override
public void onSelected(Selector aSelector) {
}
@Override
public void onAccept() {
}
@Override
public void onConnect() {
}
@Override
public boolean readFirst() {
return true;
}
@Override
public void onReadable() {
reader.fill();
_dispatchRequest();
}
//
// リクエストを読む
// ヘッダ未取得であれば,ヘッダを読む
// 接続が切られれば invalidate
// ヘッダ読み込み完了すれば ITransfer を生成
// ITransfer があれば処理を委譲
//
private void _dispatchRequest() {
if (ascent_ == null) {
if (request == null) {
request = new ClientRequest(reader);
//Util.say("client", id_, ": new clientRequest");
}
if (request.queryState() < ClientRequest.STS_HEADER) {
if (reader.available() < 0) {
Util.say("client", id_, ": wait for clientRequest... client reader.avail < 0");
wantToRead(false);
termIfIdle();
}
return;
}
ascent_ = OriginDispatcher.dispatch(this, request.host, request.port);
}
ascent_.onClientReadable(); // no work :)
}
public void notifyRequestEnd() throws Exception {
if (ascent_ == null) {
Util.say("client", id_, ": asc==null but req end ???");
return;
}
descentQ_.add(ascent_);
// 次のリクエストを待つ
request = null;
ascent_ = null;
_dispatchRequest();
}
public void notifyResponseStart() {
// レスポンスを待つ
//Util.say("client", id_, ": response will come. want to write");
_takeNextResponse();
}
@Override
public void onWritable() {
descent_.onClientWritable();
}
private void _takeNextResponse() {
if (descent_ == null) {
descent_ = descentQ_.pollFirst();
if (descent_ == null) {
Util.say("client", id_, ": no next descent");
termIfIdle();
return;
}
//Util.say("client", id_, ": GOT next descent: " + descent);
wantToWrite(true);
}
}
public void notifyResponseEnd() {
Util.say("client", id_, ": notifyResEnd");
descent_ = null;
wantToWrite(false);
_takeNextResponse();
}
public void termIfIdle() {
if (ascent_ == null && descent_ == null && descentQ_.size() == 0) {
invalidate();
}
}
public void invalidate() {
Util.say("client", id_, ": invalidate()");
Util.close(socket);
selKey_.cancel();
}
public boolean isValid() {
return selKey_.isValid();
}
@Override
public String toString() {
return "ClientPeer" + id_ + ": asc = " + ascent_ + " / dsc = " + descent_;
}
}