// @NOTE keep flush private the preQ is not threadsafe
  private void flush(SessionWrapper sessW) {
    // disconnected drop any session messages
    // optionally keep any other messages or reject back  upstream

    final Session session = sessW._session;
    final MessageQueue queue = sessW._queue;
    final MessageQueue preQ = sessW._preQueue;
    final MessageQueue syncQ = sessW._syncQueue;

    while (!syncQ.isEmpty()) {
      syncQ.next(); // DISCARD
    }

    Message head = null;
    Message tail = null;

    while (!queue.isEmpty()) {
      Message msg = queue.next();
      if (msg.getReusableType() == CoreReusableType.NullMessage) break;

      if (session.discardOnDisconnect(msg) == false) {
        if (session.rejectMessageUpstream(msg, DISCONNECTED)) {
          // message recycled by successful reject processing
        } else {
          if (tail == null) {
            head = msg;
            tail = msg;
          } else {
            tail.attachQueue(msg);
            tail = msg;
          }
        }
      } else {
        _logMsg.copy(DROP_MSG).append(msg.getReusableType().toString());
        _log.info(_logMsg);
        session.outboundRecycle(msg);
      }
    }

    // move remaining messages to the preQ

    if (head != null) {
      Message tmp = head;

      while (tmp != null) {
        Message next = tmp.getNextQueueEntry();
        tmp.detachQueue();
        preQ.add(tmp);
        tmp = next;
      }
    }
  }
 @Override
 public void dispatchForSync(Message msg) {
   if (msg != null) {
     final MessageHandler handler = msg.getMessageHandler(); // cant be null
     NonBlockingSession session = (NonBlockingSession) handler;
     MessageQueue queue = session.getSendSyncQueue();
     if (queue != null) {
       queue.add(msg);
     } else {
       // @TODO add ReusableString write( ReusableString buf ) to Message and log details
       // should NEVER happen
       _log.error(MISSING_HANDLER, ((Session) handler).getComponentId());
     }
   }
 }
  private void validateTicksize(Instrument instrument, double price) {
    TickType ts = instrument.getTickscale();

    if (ts.canVerifyPrice()) {
      if (!ts.isValid(price)) {

        delim().append(INVALID_PRICE);

        ts.writeError(price, _err);
      }
    } else {
      ReusableString msg = TLC.instance().pop();
      msg.append(MISSING_TICK).append(instrument.getRIC());
      _log.warn(msg);
      TLC.instance().pushback(msg);
    }
  }
 @Override
 public void dispatch(final Message msg) {
   if (msg != null) {
     final MessageHandler handler = msg.getMessageHandler();
     final NonBlockingSession session = (NonBlockingSession) handler;
     final MessageQueue queue = session.getSendQueue();
     if (queue != null) {
       queue.add(msg);
     } else {
       // should NEVER happen
       ReusableString s = TLC.instance().pop();
       s.copy(((Session) handler).getComponentId())
           .append(": Missing Queue, unable to dispatch : ");
       msg.dump(s);
       _log.error(MISSING_HANDLER, s);
       TLC.instance().pushback(s);
     }
   }
 }
  @Override
  public void handlerStatusChange(MessageHandler handler, boolean connected) {
    final int numSessions = _sessions.length;

    boolean allDisconnected = true;

    for (int i = 0; i < numSessions; i++) {
      SessionWrapper sessW = _sessions[i];

      if (sessW._session == handler) {
        if (connected != sessW._connected) {
          final NonBlockingSession sess = sessW._session;

          _log.info(
              "MultiSession OutDispatcher "
                  + getComponentId()
                  + " : "
                  + ((connected) ? "CONNECTED" : "DISCONNECTED")
                  + " with "
                  + sess.getComponentId()
                  + ", canHandle="
                  + sess.canHandle()
                  + ", isLoggedIn="
                  + sess.isLoggedIn());

          sessW._connected = connected;
        }
      }

      if (sessW._connected) {
        allDisconnected = false;
      }
    }

    _fullyFlushed = false;

    synchronized (_disconnectLock) { // force mem barrier
      _allDisconnected = allDisconnected;
    }

    _ctl.statusChange();
  }
  @Override
  public void handleExecutionException(Exception ex) {
    final NonBlockingSession sess = _curSessW._session;

    if (_curMsg != null && sess != null) {
      _log.warn(
          "SessionThreadedDispatcher "
              + getComponentId()
              + ", msgSeqNum="
              + _curMsg.getMsgSeqNum()
              + ", sess="
              + sess.getComponentId()
              + " exception "
              + ex.getMessage());
    }

    flush(_curSessW);

    // some problem, possibly disconnect, poke controller to wake up anything waiting on controller
    // passive lock
    _ctl.statusChange(); // Mem barrier
  }