users@grizzly.java.net

Re: Need help implementing ProtocolParser

From: Erik Svensson <erik.svensson_at_six.se>
Date: Tue, 18 Mar 2008 10:57:00 +0100

Howdy all!

I've implemented a protocol parser using Ash2K:s case as a template and I
get the same result. I send a message of somehting like 15k bytes.
I save the buffer, return wants_more_data = true and I expect the same
parser to be called again but instead a new one is created and so I lose my
saved buffer.

Running 1.7.2 with the debugger I notice that the return value from
releaseBuffer() is ignored.

Here's my protocol parser:


public class ProtocolParser implements
com.sun.grizzly.ProtocolParser<SimpleMessage> {

  private ByteBuffer saved,retain_buffer;
  private int position;
  private int limit;
  private SimpleMessage mess;
  private boolean wants_more_data = false;
  private boolean has_unparsed_data = false;

  public ProtocolParser() {
    System.out.println("Creating a new ProtocolParser");
    retain_buffer = ByteBuffer.allocateDirect(18000);
  }

  public boolean isExpectingMoreData() {
    System.out.println("isExpectingMoreData : "+wants_more_data);
    return wants_more_data;
  }

  public boolean hasMoreBytesToParse() {
    return has_unparsed_data;
  }

  public SimpleMessage getNextMessage() {
    // the call pattern should be:
    // hasNextMessage() == true
    // getNextMessage()
    // but if not:
    if (null == mess) {
      mess = extractMessage();
    }
    SimpleMessage tmp = mess;
    mess = null;

    return tmp;
  }

  public boolean hasNextMessage() {

    if (null == mess) {
      mess = extractMessage();
    }

    return ( mess != null);
  }

  public void startBuffer(ByteBuffer bb) {
    saved = bb;
    saved.flip(); // flip the byte buffer for reading. (should have been
done already)
    
    if ((saved.remaining() > retain_buffer.remaining())) {
      // grow the retain buffer...
      System.out.println("Grow retain buffer not implemented");
      return;
    }
    retain_buffer.put(saved);
    retain_buffer.flip();
    bb.clear();
  }

  public boolean releaseBuffer() {
    System.out.println("releaseBuffer : ");
    if (wants_more_data) {
      System.out.println("releaseBuffer : Doing compact");
      retain_buffer.compact();
    } else {
      retain_buffer.clear();
    }
    return wants_more_data;
  }

  private SimpleMessage extractMessage() {
    SimpleMessage message = null;

    if (!retain_buffer.hasRemaining()) {
      // there are no more readable bytes in the buffer
      // this should mean that we've read all messages in the buffer
      wants_more_data = false;
      has_unparsed_data = false;
      saved.clear(); // clean up our byte buffer. No one else will do it for
us
      return message;
    }
    // save the position before we send it off to the parser
    position = retain_buffer.position();
    message = SimpleMessage.parse(retain_buffer);
    System.out.println("parsed message is null ? "+(message == null ? "YES"
: "NO"));
    if (message == null) {
      // not enough bytes for a message
      // but we know there are bytes so there must be
      // an incomplete message there
      if (retain_buffer.position() != position) {
        retain_buffer.position(position);
      }
      wants_more_data = true;
      has_unparsed_data = false;
    } else {
      // here we have a complete message
      if (retain_buffer.limit() == retain_buffer.position()) {
        // the end of the buffer is reached.
        wants_more_data = false;
        has_unparsed_data = false;
      } else {
        has_unparsed_data = true;
        // here we can't accuratly set wants_more_data.
        // since we don't know if the bytes in the buffer is a
        // complete message or not
      }
    }
    return message;
  }
}

cheers
/Erik