Package tkuri.jxy.server

Source Code of tkuri.jxy.server.OriginPeer

/**
* (c) 2011 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.Util;
import tkuri.jxy.arch.ASelectionAttachment;
import tkuri.jxy.arch.ChannelReader;
import tkuri.jxy.arch.TheSelector;


/**
* origin server
*/
public class OriginPeer extends ASelectionAttachment {


  static int ID = 0;

  private int id_ = ID++;

  private InetSocketAddress addr_;

  private LinkedList<ITransfer> ascentQ_ = new LinkedList<ITransfer>();
  private ITransfer ascent_ = null;

  private LinkedList<ITransfer> descentQ_ = new LinkedList<ITransfer>();
  private ITransfer descent_ = null;

  SocketChannel socket = null;
  ChannelReader reader = null;
  //OriginResponse response = null;

  private SelectionKey selKey_ = null;


  /**
   * ctor
   * @param aAddr
   */
  OriginPeer(InetSocketAddress aAddr) {

    addr_ = aAddr;
  }


  void enq(ITransfer aTransfer) {

    Util.say("origin", id_, ": enqueue ", aTransfer);
    ascentQ_.add(aTransfer);
    _queryNextAscent();
  }


  private boolean _queryNextAscent() {

    if (descent_ != null) {
      wantToWrite(false);
      return false; // descent 作業中はリクエスト処理しない
    }

    if (ascent_ != null) {
      return true;
    }

    ascent_ = ascentQ_.pollFirst();
    //Util.say("origin", id_, ": next ascent " + ascent_);

    if (ascent_ != null) {
      _verifySocket();
      return true;

    } else if (reader.available() < 0) {
      Util.say("origin", id_, ": no ascent task, no data anymore.");
      _termIfIdle();

    } else {
      //Util.say("origin: no write");
      wantToWrite(false);
    }

    return false;
  }


  /*
   * verify
   */
  private void _verifySocket() {

    //Util.say("verify");

    if (socket != null) {
      if (reader.fill() < 0) {
        //Util.say("origin", id_, ": verify: origin sock closed");
        invalidate(true);
      } else {
        //Util.say("origin", id_, ": verify: origin sock living");
      }
    }

    if (socket != null) {
      ascent_.onOriginConnect(this, true);
      //Util.say("origin", id_, ": want to write");
      wantToWrite(true);
      return;
    }

    try {
      socket = SocketChannel.open();
      reader = new ChannelReader(socket);

      socket.configureBlocking(false);
      selKey_ = TheSelector.registerChannel(
          socket
          , SelectionKey.OP_CONNECT
            + SelectionKey.OP_READ
            + SelectionKey.OP_WRITE
          , this);

      Util.say("origin", id_, ": connecting: ", addr_);
      if (socket.connect(addr_)) {
        onConnect();
      } else {
        // onConnect を待つ
      }

    } catch (Exception x) {
      // このあたりで例外が出るとすれば,NIO自体に問題があるからでは?
      throw new RuntimeException(x);
    }

    //Util.say("verified");
  }


  public boolean isValid() {

    return (selKey_ != null && selKey_.isValid());
  }


  @Override
  public int interestOps() {

    if (isValid()) {
      return selKey_.interestOps();
    }

    return 0;
  }


  @Override
  public void interestOps(int aOps) {

    if (isValid()) {
      selKey_.interestOps(aOps);
    }
  }


  /**
   *
   * @return
   */
  public boolean isConnected() {

    return (socket != null) ? socket.isConnected() : false;
  }


  private void _termIfIdle() {

    if (ascent_ == null && ascentQ_.size() == 0
        && descent_ == null && descentQ_.size() == 0) {

      invalidate(true);
    }
  }


  public void invalidate(boolean aClose) {

    if (aClose && socket != null) {
      Util.say("origin", id_, ": invalidate(true)");
      Util.close(socket);
      selKey_.cancel();
      socket = null;
      reader = null;
      selKey_ = null;
    }
  }


  @Override
  public void onSelected(Selector aSelector) {
  }


  @Override
  public void onAccept() {
  }


  @Override
  public void onConnect() {

    interestOps(interestOps() & (~SelectionKey.OP_CONNECT));
    ascent_.onOriginConnect(this, false);
  }


  public boolean readFirst() {

    return false;
  }


  @Override
  public void onWritable() {

    if (! _queryNextAscent()) {
      return;
    }
    if (! isValid() || !isConnected()) {
      return;
    }

    ascent_.onOriginWritable();
  }


  public void notifyRequestEnd() {

    if (ascent_ == null) {
      Util.say("origin", id_, ": why ascent = null?");
      return;
    }
    descent_ = ascent_;
    wantToWrite(false);
    //wantToRead(true);

    // descentQ_.add(ascent_);キューにする必要ない...
    // ascent_ = null; だめ.レスポンス完了するまで次のリクエストをしたくない.Conn:closeされるかもしれないし...
  }


  @Override
  public void onReadable() {

    if (! isValid() || !isConnected()) {
      return;
    }

    reader.fill();
    //Util.say("origin", id_, ": length: ", reader.length());

    if (descent_ == null) {
      descent_ = descentQ_.pollFirst();
      if (descent_ == null) {
        Util.say("origin", id_, ": no next descent.");
        _termIfIdle();
        return;
      }
      //Util.say("origin", id_, ": next descent " + descent_);
    }

    descent_.onOriginReadable();
  }


  public void notifyResponseEnd() {

    descent_ = null;
    ascent_ = null;
    //wantToRead(false);
    _queryNextAscent();
  }


  @Override
  public String toString() {

    return "OriginPeer" + id_ + ": asc = " + ascent_ + " / dsc = " + descent_
        + " / descQsize = " + descentQ_.size();
  }
}
TOP

Related Classes of tkuri.jxy.server.OriginPeer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.