users@grizzly.java.net

Re: XML Input over TCP with Grizzly

From: Oleksiy Stashok <Oleksiy.Stashok_at_Sun.COM>
Date: Fri, 21 Mar 2008 12:27:18 +0100

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
>
>