@Override
  public void messageReceived(NextFilter nextFilter, final IoSession session, Object message)
      throws Exception {

    int maxReadThroughput = this.maxReadThroughput;
    // process the request if our max is greater than zero
    if (maxReadThroughput > 0) {
      final State state = (State) session.getAttribute(STATE);
      long currentTime = System.currentTimeMillis();

      long suspendTime = 0;
      boolean firstRead = false;
      synchronized (state) {
        state.readBytes += messageSizeEstimator.estimateSize(message);

        if (!state.suspendedRead) {
          if (state.readStartTime == 0) {
            firstRead = true;
            state.readStartTime = currentTime - 1000;
          }

          long throughput = (state.readBytes * 1000 / (currentTime - state.readStartTime));
          if (throughput >= maxReadThroughput) {
            suspendTime =
                Math.max(
                    0,
                    state.readBytes * 1000 / maxReadThroughput
                        - (firstRead ? 0 : currentTime - state.readStartTime));

            state.readBytes = 0;
            state.readStartTime = 0;
            state.suspendedRead = suspendTime != 0;

            adjustReadBufferSize(session);
          }
        }
      }

      if (suspendTime != 0) {
        session.suspendRead();
        scheduledExecutor.schedule(
            new Runnable() {
              public void run() {
                synchronized (state) {
                  state.suspendedRead = false;
                }
                session.resumeRead();
              }
            },
            suspendTime,
            TimeUnit.MILLISECONDS);
      }
    }

    nextFilter.messageReceived(session, message);
  }
  @Override
  public void messageSent(NextFilter nextFilter, final IoSession session, WriteRequest writeRequest)
      throws Exception {

    int maxWriteThroughput = this.maxWriteThroughput;
    // process the request if our max is greater than zero
    if (maxWriteThroughput > 0) {
      final State state = (State) session.getAttribute(STATE);
      long currentTime = System.currentTimeMillis();

      long suspendTime = 0;
      boolean firstWrite = false;
      synchronized (state) {
        state.writtenBytes += messageSizeEstimator.estimateSize(writeRequest.getMessage());
        if (!state.suspendedWrite) {
          if (state.writeStartTime == 0) {
            firstWrite = true;
            state.writeStartTime = currentTime - 1000;
          }

          long throughput = (state.writtenBytes * 1000 / (currentTime - state.writeStartTime));
          if (throughput >= maxWriteThroughput) {
            suspendTime =
                Math.max(
                    0,
                    state.writtenBytes * 1000 / maxWriteThroughput
                        - (firstWrite ? 0 : currentTime - state.writeStartTime));

            state.writtenBytes = 0;
            state.writeStartTime = 0;
            state.suspendedWrite = suspendTime != 0;
          }
        }
      }

      if (suspendTime != 0) {
        log.trace("Suspending write");
        session.suspendWrite();
        scheduledExecutor.schedule(
            new Runnable() {
              public void run() {
                synchronized (state) {
                  state.suspendedWrite = false;
                }
                session.resumeWrite();
                log.trace("Resuming write");
              }
            },
            suspendTime,
            TimeUnit.MILLISECONDS);
      }
    }

    nextFilter.messageSent(session, writeRequest);
  }