XML Input over TCP with Grizzly

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

XML Input over TCP with Grizzly

William Beene-2
Hi,
        I am using Grizzly for an application at work. The goal is to accept an
XML message over a TCP socket and then pass it on to another part of the
application. The problem I am having is that my XML message gets split
up if the XML message isn't super small. The test message I am using is
26 kb and gets split up into several pieces. I've read that I can use
context to keep track of information for further processing. And I was
planning on using SAX to get an event for the end of the document so I
would know when it has finished. I'm not set on this solution, but I
can't seem to figure out how to do this. Any advice will be much
appreciated.

Thanks,
William Beene


This message is for the designated recipient only and may contain privileged, proprietary, or otherwise private information.  If you have received it in error, please notify the sender immediately and delete the original.  Any other use of the email by you is prohibited.

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: XML Input over TCP with Grizzly

Erik Svensson-3
Hi,
I am using Grizzly for an application at work. The goal is to accept an
XML message over a TCP socket and then pass it on to another part of the
application. The problem I am having is that my XML message gets split
up if the XML message isn't super small. The test message I am using is
26 kb and gets split up into several pieces. I've read that I can use
context to keep track of information for further processing. And I was
planning on using SAX to get an event for the end of the document so I
would know when it has finished. I'm not set on this solution, but I
can't seem to figure out how to do this. Any advice will be much
appreciated.

This has been a bit of a topic lately.
The thread ' Need help implementing ProtocolParser' was about this.
I'm attaching a protocol parser that seems to be able to handle messages spread out over several reads ('seems to' because 
I've only tested it with a few test cases). It uses Oleksiys idea of  allocating a new byte buffer and attaching it to the current
worker thread.

Anyhoo, here's the code:

package se.phlogiston.grizzly.overflow;
import se.phlogiston.grizzly.tutorial2.SimpleMessage;
import java.nio.ByteBuffer;
import com.sun.grizzly.util.ByteBufferFactory;import com.sun.grizzly.util.WorkerThread;
/** * Created by IntelliJ IDEA. * User: erik * Date: Mar 14, 2008 * Time: 10:05:24 PM * To change this template use File | Settings | File Templates. */public class ProtocolParser implements com.sun.grizzly.ProtocolParser<SimpleMessage> {
  private ByteBuffer saved;  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");  }
  public boolean isExpectingMoreData() {    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)  }
  public boolean releaseBuffer() {    if (wants_more_data) {      saved.compact();      // check to see if we made room in the buffer...      // compact sets the position at the end of the written/moved bytes so remaining()      // shows how much more we can stuff into the buffer.      if (saved.remaining() == 0 ) {        System.out.println("No space left in the buffer. Extendening the buffer.");        reallocateSaved();      }    } else {      saved.clear();    }    // Grizzly doesn't seem to care (and doesn't when you look at the code) but we return a factual value anyhoo    return wants_more_data;  }

  private void reallocateSaved() {    saved.position(position);    ByteBuffer tmpBuffer =            ByteBufferFactory.allocateView(saved.capacity() * 2, false);    System.out.println("reallocateBuffer newly created : pos :  "+tmpBuffer.position()+" limit: "+tmpBuffer.limit()+"" +" cap: "+            tmpBuffer.capacity());
    tmpBuffer.put(saved);    saved = tmpBuffer;     ((WorkerThread) Thread.currentThread()).setByteBuffer(saved);  }
  private SimpleMessage extractMessage() {    SimpleMessage message = null;
    if (!saved.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 = saved.position();    message = SimpleMessage.parse(saved);
    if (message == null) {      // not enough bytes for a message      // but we know there are bytes so there must be      // an incomplete message there      if (saved.position() != position) {        saved.position(position);      }      wants_more_data = true;      has_unparsed_data = false;    } else {      // here we have a complete message      if (saved.limit() == saved.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


Reply | Threaded
Open this post in threaded view
|

Re: XML Input over TCP with Grizzly

Oleksiy Stashok
Hello William,

I agree with Erik, seems his usecase is similar to yours.
Wanted just to get more info on that....

How you're planning to parse incoming data?

Let's say you're not sure whether all data came or not. You're parsing data and then SAX parser notifies you about some XML error (malformed document or similar), this could mean either coming data has error or not whole XML document was read.
I will not look at case, where wrong XML came, but let's say read operation read just half of XML document. What you're planning to do then? Read second half, attach it to the first one and try to parse XML document from the beginning? Or?

Just want to understand better the usecase you have :)

Thank you.

WBR,
Alexey.

On Mar 20, 2008, at 21:21 , Erik Svensson wrote:
Hi,
I am using Grizzly for an application at work. The goal is to accept an
XML message over a TCP socket and then pass it on to another part of the
application. The problem I am having is that my XML message gets split
up if the XML message isn't super small. The test message I am using is
26 kb and gets split up into several pieces. I've read that I can use
context to keep track of information for further processing. And I was
planning on using SAX to get an event for the end of the document so I
would know when it has finished. I'm not set on this solution, but I
can't seem to figure out how to do this. Any advice will be much
appreciated.

This has been a bit of a topic lately.
The thread ' Need help implementing ProtocolParser' was about this.
I'm attaching a protocol parser that seems to be able to handle messages spread out over several reads ('seems to' because 
I've only tested it with a few test cases). It uses Oleksiys idea of  allocating a new byte buffer and attaching it to the current
worker thread.

Anyhoo, here's the code:

package se.phlogiston.grizzly.overflow;
import se.phlogiston.grizzly.tutorial2.SimpleMessage;
import java.nio.ByteBuffer;
import com.sun.grizzly.util.ByteBufferFactory;import com.sun.grizzly.util.WorkerThread;
/** * Created by IntelliJ IDEA. * User: erik * Date: Mar 14, 2008 * Time: 10:05:24 PM * To change this template use File | Settings | File Templates. */public class ProtocolParser implements com.sun.grizzly.ProtocolParser<SimpleMessage> {
  private ByteBuffer saved;  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");  }
  public boolean isExpectingMoreData() {    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)  }
  public boolean releaseBuffer() {    if (wants_more_data) {      saved.compact();      // check to see if we made room in the buffer...      // compact sets the position at the end of the written/moved bytes so remaining()      // shows how much more we can stuff into the buffer.      if (saved.remaining() == 0 ) {        System.out.println("No space left in the buffer. Extendening the buffer.");        reallocateSaved();      }    } else {      saved.clear();    }    // Grizzly doesn't seem to care (and doesn't when you look at the code) but we return a factual value anyhoo    return wants_more_data;  }

  private void reallocateSaved() {    saved.position(position);    ByteBuffer tmpBuffer =            ByteBufferFactory.allocateView(saved.capacity() * 2, false);    System.out.println("reallocateBuffer newly created : pos :  "+tmpBuffer.position()+" limit: "+tmpBuffer.limit()+"" +" cap: "+            tmpBuffer.capacity());
    tmpBuffer.put(saved);    saved = tmpBuffer;     ((WorkerThread) Thread.currentThread()).setByteBuffer(saved);  }
  private SimpleMessage extractMessage() {    SimpleMessage message = null;
    if (!saved.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 = saved.position();    message = SimpleMessage.parse(saved);
    if (message == null) {      // not enough bytes for a message      // but we know there are bytes so there must be      // an incomplete message there      if (saved.position() != position) {        saved.position(position);      }      wants_more_data = true;      has_unparsed_data = false;    } else {      // here we have a complete message      if (saved.limit() == saved.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