Package com.barchart.udt.nio

Source Code of com.barchart.udt.nio.SelectionKeyUDT

/**
* Copyright (C) 2009-2013 Barchart, Inc. <http://www.barchart.com/>
*
* All rights reserved. Licensed under the OSI BSD License.
*
* http://www.opensource.org/licenses/bsd-license.php
*/
package com.barchart.udt.nio;

import java.nio.channels.CancelledKeyException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.barchart.udt.EpollUDT;
import com.barchart.udt.EpollUDT.Opt;
import com.barchart.udt.SocketUDT;

/**
* UDT selection key implementation.
*/
public class SelectionKeyUDT extends SelectionKey implements
    Comparable<SelectionKeyUDT> {

  protected static final int HAS_READ = OP_ACCEPT | OP_READ;

  protected static final int HAS_WRITE = OP_CONNECT | OP_WRITE;

  protected static final Logger log = LoggerFactory
      .getLogger(SelectionKeyUDT.class);

  /**
   * select options : from jdk into epoll
   */
  protected static Opt from(final int interestOps) {

    final boolean hasRead = (interestOps & HAS_READ) != 0;
    final boolean hasWrite = (interestOps & HAS_WRITE) != 0;

    if (hasRead && hasWrite) {
      return Opt.BOTH;
    }

    if (hasRead) {
      return Opt.READ;
    }

    if (hasWrite) {
      return Opt.WRITE;
    }

    return Opt.NONE;

  }

  public static final String toStringOps(final int selectOps) {
    final char A = (OP_ACCEPT & selectOps) != 0 ? 'A' : '-';
    final char C = (OP_CONNECT & selectOps) != 0 ? 'C' : '-';
    final char R = (OP_READ & selectOps) != 0 ? 'R' : '-';
    final char W = (OP_WRITE & selectOps) != 0 ? 'W' : '-';
    return String.format("%c%c%c%c", A, C, R, W);
  }

  /** bound channel */
  private final ChannelUDT channelUDT;

  /** current interest options in epoll format */
  private volatile Opt epollOpt;

  /** requested interest */
  private volatile int interestOps;

  /** is key not canceled? */
  private volatile boolean isValid;

  /** read and write correlation index for the same key */
  private volatile int resultIndex;

  /** interest reported as ready */
  private volatile int readyOps;

  /** bound selector */
  private final SelectorUDT selectorUDT;

  protected SelectionKeyUDT( //
      final SelectorUDT selectorUDT, //
      final ChannelUDT channelUDT, //
      final Object attachment //
  ) {

    this.selectorUDT = selectorUDT;
    this.channelUDT = channelUDT;

    super.attach(attachment);

    makeValid(true);

  }

  /**
   * ensure key is not canceled
   */
  protected void assertValidKey() throws CancelledKeyException {
    if (isValid()) {
      return;
    }
    throw new CancelledKeyException();
  }

  /**
   * ensure only permitted mask bits
   */
  protected void assertValidOps(final int interestOps) {
    if ((interestOps & ~(channel().validOps())) != 0) {
      throw new IllegalArgumentException("invalid interestOps="
          + interestOps);
    }
  }

  @Override
  public void cancel() {
    if (isValid()) {
      selector().cancel(this);
    }
  }

  @Override
  public SelectableChannel channel() {
    return (SelectableChannel) channelUDT;
  }

  protected ChannelUDT channelUDT() {
    return channelUDT;
  }

  @Override
  public int compareTo(final SelectionKeyUDT that) {
    final int thisId = this.socketId();
    final int thatId = that.socketId();
    if (thisId > thatId) {
      return +1;
    }
    if (thisId < thatId) {
      return -1;
    }
    return 0;
  }

  /**
   * Apply read readiness according to {@link KindUDT} channel role.
   * <p>
   * note: read readiness is reported before {@link #doWrite(int)}
   *
   * @return should report state change?
   */
  protected boolean doRead(final int resultIndex) {

    int readyOps = 0;
    final int interestOps = this.interestOps;
    this.resultIndex = resultIndex;

    try {

      if (!epollOpt.hasRead()) {
        if (interestOps == 0) {
          logError("error report when missing interest");
          return false;
        } else {
          readyOps = interestOps;
          return true;
        }
      }

      switch (kindUDT()) {
      case ACCEPTOR:
        if ((interestOps & OP_ACCEPT) != 0) {
          readyOps = OP_ACCEPT;
          return true;
        } else {
          logError("ready to ACCEPT while not interested");
          return false;
        }
      case CONNECTOR:
      case RENDEZVOUS:
        if ((interestOps & OP_READ) != 0) {
          readyOps = OP_READ;
          return true;
        } else {
          logError("ready to READ while not interested");
          return false;
        }
      default:
        logError("wrong kind");
        return false;
      }

    } finally {

      this.readyOps = readyOps;

    }

  }

  /**
   * Apply write readiness according to {@link KindUDT} channel role.
   * <p>
   * note: write readiness is reported after {@link #doRead(int)}
   *
   * @return should report state change?
   */
  protected boolean doWrite(final int resultIndex) {

    int readyOps = 0;
    final int interestOps = this.interestOps;
    final boolean hadReadBeforeWrite = this.resultIndex == resultIndex;

    try {

      if (!epollOpt.hasWrite()) {
        if (interestOps == 0) {
          logError("error report when missing interest");
          return false;
        } else {
          readyOps = interestOps;
          return true;
        }
      }

      switch (kindUDT()) {
      case ACCEPTOR:
        logError("ready to WRITE for acceptor");
        return false;
      case CONNECTOR:
      case RENDEZVOUS:
        if (channelUDT().isConnectFinished()) {
          if ((interestOps & OP_WRITE) != 0) {
            readyOps = OP_WRITE;
            return true;
          } else {
            logError("ready to WRITE when not insterested");
            return false;
          }
        } else {
          if ((interestOps & OP_CONNECT) != 0) {
            readyOps = OP_CONNECT;
            return true;
          } else {
            logError("ready to CONNECT when not interested");
            return false;
          }
        }
      default:
        logError("wrong kind");
        return false;
      }

    } finally {
      if (hadReadBeforeWrite) {
        this.readyOps |= readyOps;
      } else {
        this.readyOps = readyOps;
      }
    }

  }

  protected Opt epollOpt() {
    return epollOpt;
  }

  protected EpollUDT epollUDT() {
    return selector().epollUDT();
  }

  @Override
  public boolean equals(final Object otherKey) {
    if (otherKey instanceof SelectionKeyUDT) {
      final SelectionKeyUDT other = (SelectionKeyUDT) otherKey;
      return other.socketId() == this.socketId();
    }
    return false;
  }

  @Override
  public int hashCode() {
    return socketId();
  }

  @Override
  public int interestOps() {

    return interestOps;

  }

  @Override
  public SelectionKey interestOps(final int interestOps) {

    assertValidKey();
    assertValidOps(interestOps);

    try {

      final Opt epollNew = from(interestOps);

      if (epollNew != epollOpt) {

        if (Opt.NONE == epollNew) {
          epollUDT().remove(socketUDT());
        } else {
          epollUDT().remove(socketUDT());
          epollUDT().add(socketUDT(), epollNew);
        }

        epollOpt = epollNew;

      }

    } catch (final Exception e) {

      log.error("epoll udpate failure", e);

    } finally {

      this.interestOps = interestOps;

    }

    return this;

  }

  @Override
  public boolean isValid() {
    return isValid;
  }

  protected KindUDT kindUDT() {
    return channelUDT.kindUDT();
  }

  protected void logError(final String comment) {

    final String message = "logic error : \n\t" + this;

    log.warn(message, new Exception("" + comment));

  }

  /** add/remove poll/socket registration */
  protected void makeValid(final boolean isValid) {
    try {
      if (isValid) {
        epollOpt = Opt.NONE;
        epollUDT().add(socketUDT(), epollOpt);
      } else {
        epollUDT().remove(socketUDT());
      }
    } catch (final Exception e) {
      log.error("epoll failure", e);
    } finally {
      this.isValid = isValid;
    }
  }

  @Override
  public int readyOps() {

    return readyOps;

  }

  protected void readyOps(final int ops) {

    readyOps = ops;

  }

  @Override
  public SelectorUDT selector() {
    return selectorUDT;
  }

  protected int socketId() {
    return socketUDT().id();
  }

  protected SocketUDT socketUDT() {
    return channelUDT.socketUDT();
  }

  @Override
  public String toString() {

    return String
        .format("[id: 0x%08x] poll=%s ready=%s inter=%s %s %s %s bind=%s:%s peer=%s:%s", //
            socketUDT().id(), //
            epollOpt, //
            toStringOps(readyOps), //
            toStringOps(interestOps), //
            channelUDT.typeUDT(), //
            channelUDT.kindUDT(), //
            socketUDT().status(), //
            socketUDT().getLocalInetAddress(), //
            socketUDT().getLocalInetPort(), //
            socketUDT().getRemoteInetAddress(), //
            socketUDT().getRemoteInetPort() //
        );

  }

}
TOP

Related Classes of com.barchart.udt.nio.SelectionKeyUDT

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.