users@grizzly.java.net

ProtocolParser redux

From: Erik Svensson <erik.svensson_at_six.se>
Date: Mon, 11 Feb 2008 14:18:12 +0100

Howdy folks,

Now I finally have a working ProtocolParser and ParserProtocolFilter.
To get it working was a journey of discovery and I found a strange thing or
two.

I wrote a a ProtocolParser, a ParserProtocolFilter and set it up like this:

   controller.setProtocolChainInstanceHandler(new
DefaultProtocolChainInstanceHandler() {
        public ProtocolChain poll() {
          ProtocolChain protocol_chain = protocolChains.poll();
          if (protocol_chain == null) {
            protocol_chain = new DefaultProtocolChain();
            protocol_chain.addFilter(parse_filter); // the parser protocol
filter
            protocol_chain.addFilter(xflow_handler); // the module that will
do something intelligent with the created message
            offer(protocol_chain);
          }
          return protocol_chain;
        }
      }); // end overridden method
 
I created a client (with grizzly) that sent 10 messages and the quit.
I fired everything up and found that my server would only read one message
and no more. I fiddled around and finally downloaded the grizzly source and
started the debugger. The incoming byte buffer contained all 10 messages.
The protoocl parser extracted the first message correctly and reported
more_bytes_to_parse as it should to report that there were more messages
that needed handling. To no avail. After a lot of tracing (the fun things
you do on a Saturday evening in front of the telly with the kids singing
along to the eurovision song contest) I found the following snippet:

        if (continousExecution
            && currentPosition == protocolFilters.size() -1
            && (Boolean)ctx.removeAttribute(ProtocolFilter.SUCCESSFUL_READ)
                == Boolean.TRUE) {
            reinvokeChain = true;
        }

where 'continousExecution' looked interesting. Looking through the javadocs
I found a method for setting it in DefaultProtocolChain. Changing my
code above to the not-so-elegant:

   controller.setProtocolChainInstanceHandler(new
DefaultProtocolChainInstanceHandler() {
        public ProtocolChain poll() {
          ProtocolChain protocol_chain = protocolChains.poll();
          if (protocol_chain == null) {
            protocol_chain = new DefaultProtocolChain();
            protocol_chain.addFilter(parse_filter);
            protocol_chain.addFilter(xflow_handler);
        ((DefaultProtocolChain)protocol_chain).setContinuousExecution(true);
// ugly
            
            offer(protocol_chain);
                   
          }
          return protocol_chain;
        }
      }); // end overridden method

Now things works as it should!

Now I'm wondering about this. Why isn't the procotol chain re-invoked by
default if the byte buffer isn't empty? If we read again from the socket,
the remaining bytes from before are still there (unless something/someone
clears the buffer which means we lose messages) which means that we parse a
message that we recievced in the previous read. This inevitably means that
we will be behind on handling messages or maybe not handle some messages at
all.
I therefor propose that the default behaviour is as if continousExecution is
true. PostExecute() could be rewritten to provide state information on
whether or not the chain should be re-invoked and act on that.
If that is not palatable, how about adding the setContinousExecution()
method to the ProtocolChain interface?

cheers
/Erik Svensson, SIX AB