예제 #1
0
final class TimeoutNotifier implements ITimeoutNotifier {

  private final Object m_subject;
  private final TimeoutAdmin m_admin;
  private BiListNode<TimeoutEvent> m_node;
  private ITimeoutListener m_listener;
  private IState m_state = Unscheduled.getInstance();
  private final ReentrantLock m_lock;

  TimeoutNotifier(Object subject, TimeoutAdmin admin) {
    m_subject = subject;
    m_admin = admin;
    m_lock = new ReentrantLock();
  }

  interface IState {

    public boolean schedule(TimeoutNotifier notifier, int timeout);

    public boolean cancel(TimeoutNotifier notifier);

    public boolean reset(TimeoutNotifier notifier);

    public void close(TimeoutNotifier notifier);

    public int state();
  }

  static final class Scheduled implements IState {

    private static final IState m_inst = new Scheduled();

    public static IState getInstance() {
      return m_inst;
    }

    @Override
    public boolean schedule(TimeoutNotifier notifier, int timeout) {
      notifier.getTimeoutAdmin().reschedule(notifier, timeout);
      return true;
    }

    @Override
    public boolean cancel(TimeoutNotifier notifier) {
      notifier.getTimeoutAdmin().cancel(notifier);
      notifier.changeState(Unscheduled.getInstance());
      return true;
    }

    @Override
    public boolean reset(TimeoutNotifier notifier) {
      return false;
    }

    @Override
    public void close(TimeoutNotifier notifier) {
      notifier.getTimeoutAdmin().cancel(notifier);
      notifier.changeState(Closed.getInstance());
    }

    @Override
    public int state() {
      return SCHEDULED;
    }
  }

  static final class Unscheduled implements IState {

    private static final IState m_inst = new Unscheduled();

    public static IState getInstance() {
      return m_inst;
    }

    @Override
    public boolean schedule(TimeoutNotifier notifier, int timeout) {
      notifier.getTimeoutAdmin().schedule(notifier, timeout);
      notifier.changeState(Scheduled.getInstance());
      return true;
    }

    @Override
    public boolean cancel(TimeoutNotifier notifier) {
      return true;
    }

    @Override
    public boolean reset(TimeoutNotifier notifier) {
      return false;
    }

    @Override
    public void close(TimeoutNotifier notifier) {
      notifier.changeState(Closed.getInstance());
    }

    @Override
    public int state() {
      return UNSCHEDULED;
    }
  }

  static final class TimedOut implements IState {

    private static final IState m_inst = new TimedOut();

    public static IState getInstance() {
      return m_inst;
    }

    @Override
    public boolean schedule(TimeoutNotifier notifier, int timeout) {
      return false;
    }

    @Override
    public boolean cancel(TimeoutNotifier notifier) {
      return false;
    }

    @Override
    public boolean reset(TimeoutNotifier notifier) {
      notifier.changeState(Unscheduled.getInstance());
      return true;
    }

    @Override
    public void close(TimeoutNotifier notifier) {
      notifier.changeState(Closed.getInstance());
    }

    @Override
    public int state() {
      return TIMEDOUT;
    }
  }

  static final class Closed implements IState {

    private static final IState m_inst = new Closed();

    public static IState getInstance() {
      return m_inst;
    }

    @Override
    public boolean cancel(TimeoutNotifier notifier) {
      return false;
    }

    @Override
    public boolean schedule(TimeoutNotifier notifier, int timeout) {
      return false;
    }

    @Override
    public boolean reset(TimeoutNotifier notifier) {
      return false;
    }

    @Override
    public void close(TimeoutNotifier notifier) {}

    @Override
    public int state() {
      return CLOSED;
    }
  }

  @Override
  public Object getSubject() {
    return m_subject;
  }

  @Override
  public int state() {
    return m_state.state();
  }

  @Override
  public boolean schedule(int timeout) {
    if (timeout < 1) throw new IllegalArgumentException();

    final ReentrantLock lock = m_lock;
    if (!lock.tryLock()) // fail-fast
    return false;

    try {
      return m_state.schedule(this, timeout);
    } finally {
      lock.unlock();
    }
  }

  @Override
  public boolean cancel() {
    final ReentrantLock lock = m_lock;
    if (!lock.tryLock()) // fail-fast
    return false;

    try {
      return m_state.cancel(this);
    } finally {
      lock.unlock();
    }
  }

  @Override
  public boolean reset() {
    final ReentrantLock lock = m_lock;
    if (!lock.tryLock()) // fail-fast
    return false;

    try {
      return m_state.reset(this);
    } finally {
      lock.unlock();
    }
  }

  @Override
  public void close() {
    final ReentrantLock lock = m_lock;
    lock.lock();
    try {
      m_state.close(this);
    } finally {
      lock.unlock();
    }
  }

  @Override
  public void setListener(ITimeoutListener listener) {
    m_listener = listener;
  }

  void onTimeout(int hand) {
    final ReentrantLock lock = m_lock;
    // If the lock cannot be acquired, which means this notifier is being
    // cancelled or rescheduled or closed, just skip.
    if (!lock.tryLock()) return;

    try {
      // If this notifier is not in the same timeout sublist,
      // which means it has been cancelled or rescheduled,
      // then skip.
      TimeoutEvent event = m_node.get();
      if (event == null || hand != event.getIndex()) return;

      if (event.getTimeLeft() < 1) {
        changeState(TimedOut.getInstance());
        m_admin.fireTimeout(this);
      } else m_admin.scheduleNextRound(this);
    } finally {
      lock.unlock();
    }
  }

  ITimeoutListener getListener() {
    return m_listener;
  }

  // Set when scheduled
  void setNode(BiListNode<TimeoutEvent> node) {
    m_node = node;
  }

  // Cleared when cancelled or timeout
  void clearNode() {
    m_node = null;
  }

  TimeoutAdmin getTimeoutAdmin() {
    return m_admin;
  }

  BiListNode<TimeoutEvent> getNode() {
    return m_node;
  }

  void changeState(IState state) {
    m_state = state;
  }
}
예제 #2
0
 @Override
 public boolean cancel(TimeoutNotifier notifier) {
   notifier.getTimeoutAdmin().cancel(notifier);
   notifier.changeState(Unscheduled.getInstance());
   return true;
 }
예제 #3
0
 @Override
 public boolean reset(TimeoutNotifier notifier) {
   notifier.changeState(Unscheduled.getInstance());
   return true;
 }