> 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