dev@grizzly.java.net

ByteBufferStreams integration question

From: John ROM <snake-john_at_gmx.de>
Date: Wed, 19 Nov 2008 15:50:23 +0100

cc'ing to dev_at_grizzly.dev.java.net, because we might discuss this in today's project meeting:

Hi Ken,

I just would like to get your opinion:

As you know I'm integrating ByteBufferStreams into Grizzly 2.0

Now on the Server side Alexey and I see 2 Usecases for the Reader of ByteBufferStreams:

In the first Usecase the StreamReader does not really need a BlockingQueue.
As soon as bytes arrive they will be handed to StreamReader 's receiveData() and the
same Thread will be consuming data with StreamReader 's getXXX Methods.

I would like to just show you Server side pseudo-code to make it clear
(please forgive the uglyness ):


Transport.setMemoryManager(new SlabMemoryManager ());
chain.addFilter(new TransportFilter());
chain.addFilter(new ByteStreamFilter());
chain.addFilter(new CustomProtocolParserFilter ());

The ByteStreamFilter basicly creates and holds onto a StreamReader per Connection and calls
StreamReader.receiveData(..)

And here's code Alexey proposed for the CustomProtocolParserFilter:

class CustomProtocolParserFilter extends FilterAdapter {
    private Attribute preparsedMessageAttribute =.....;

    public NextAction handleRead(Context ctx, NextAction action) {
        Connection connection = ctx.getConnection();
        CustomMessage preparsedMessage = preparsedMessageAttribute.get(connection);
        if (preparsedMessage == null) {
            preparsedMessage = new CustomMessage();
        }
        StreamReader reader = ((Stream) ctx.getMessage()).getReader();
        int parsingState = preparsedMessage.getParsingState();

        while (isParsing) {
            switch (parsingState) {
                case 0:
                    if (reader.isAvailable(4)) {
                        preparsedMessage.setA(reader.getInt());
                        preparsedMessage.setParsingState(++parsingState);
                    } else {
                        isParsing = false;
                    }
                    break;
                case 1:
                    if (reader.isAvailable(8)) {
                        preparsedMessage.setB(reader.getLong());
                        preparsedMessage.setParsingState(++parsingState);
                    } else {

                        isParsing = false;
                    }
                    break;
                case 2:
                    if (reader.isAvailable(2)) {
                        preparsedMessage.setB(reader.getShort());
                        preparsedMessage.setParsingState(++parsingState);
                    } else {
                        isParsing = false;
                    }
                    break;
                case 3:
                    if(reader.isAvailable(1)) {
                        preparsedMessage.setB(reader.getByte());
                        preparsedMessage.setParsingState(++parsingState);
                    } else {
                        isParsing = false;
                    }
                    break;
            }
        }

        if (parsingState < 3) {
            preparsedMessageAttribute.set(connection, preparsedMessage);
            action.setNextAction(RETURN); // Didn't complete message parsing
        } else {
            ctx.setMessage(preparsedMessage);
        }

        return action;
    }
}


In this second usecase I want to make use of the StreamReader's BlockingQueue.
Grizzly just becomes a producer for the StreamReader and hands of the StreamReader to the Domain Logic Layer which will be running in a seperate Thread.
So again you set up:

Transport.setMemoryManager(new SlabMemoryManager ());
chain.addFilter(new TransportFilter());
chain.addFilter(new ByteStreamFilter());
chain.addFilter(new DomainLogicFilter ());

Now a DomainLogicFilter only gets called once per connection and hands over a Reader to the Domain Logic Layer. From then on Grizzly will just call Reader.receiveData(..) and go back waiting for
Read Events.

Actually I would like Grizzly to support this usecase out of the box.
In the moment I think you would have to provide a framework way to configure a DomainLogic running ThreadPool and also you would need to provide a easy way to define a ByteStreamFilter Protocol which basicly just enables having n Readers per connection.

I just would like to get your feedback because maybe this second usecase is too special and one
should just implement the first usecase and let users construct their own solution with the ByteBufferStream classes available in Grizzly 2.0

Many Greetings
John

-- 
Psssst! Schon vom neuen GMX MultiMessenger gehört? Der kann`s mit allen: http://www.gmx.net/de/go/multimessenger