dev@grizzly.java.net

Re: Grizzly 2.0: Smart codec

From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
Date: Tue, 16 Dec 2008 11:18:56 -0500

Salut,

looks good...see comment inline. We should look at Hubert reference as
well (and make sure the licence allow us to use it).

Oleksiy Stashok wrote:
> Hi,
>
> I'd like to receive some feedback on feature we've just added to Grizzly
> 2.0 workspace, named smart codec (smart filter or smart transformer) :)
> I called it "smart", because using this codec we don't need to write any
> parsers for custom messages. The codec analyzes class structure and
> performs encoding/decoding according to the type structure. There are
> some annotations, which could be used in order to change the default
> transformation logic.
>
> How it looks like?
>
> 1) First of all we define our custom message class. As example I'll take
> GIOP message:
>
> /public class GIOPMessage {/
> / private byte G;/
> / private byte I;/
> / private byte O;/
> / private byte P;/
> /
> /
> / private byte major;/
> / private byte minor;/
> /
> /
> / private byte flags;/
> / private byte value;/
> /
> /
> / private int bodyLength;/
> /
> /
> */ @Sequence(/*
> */ size=_at_Size(ref="bodyLength"),/*
> */ limit=_at_Limit(8192)/*
> */ )/*
> / private byte[] body;/
> /
> /
> / public GIOPMessage() {/
> / }/
> /
> /
> / public GIOPMessage(byte major, byte minor,/
> / byte flags, byte value, byte[] body) {/
> / G = 'G';/
> / I = 'I';/
> / O = 'O';/
> / P = 'P';/
> /
> /
> / this.major = major;/
> / this.minor = minor;/
> / this.flags = flags;/
> / this.value = value;/
> / /
> / bodyLength = body.length;/
> / this.body = body;/
> / }/
> /}/
>
> GIOP message contains of header (12 bytes) and body.
> The interesting part here, is how we define body byte array. We use
> annotation @Sequence, and define, that body length is located in
> "bodyLength" field of the same object, and maximum body size is 8192.
>
> 2) Server part....
>
> / // Create TCP NIO transport/
> / TCPNIOTransport transport =
> TransportFactory.getInstance().createTCPTransport();/
> /
> /
> / // Initialize smart Codec/
> /* SmartCodec smartCodec = new SmartCodec(GIOPMessage.class);*/
> /
> /
> / // Add filters to the chain/
> / transport.getFilterChain().add(new TransportFilter());/
> /* transport.getFilterChain().add(new SmartFilter(smartCodec));*/
> */
> /*
> / // GIOPProcessorFilter works with GIOPMessage, not with Buffers
> /
> / transport.getFilterChain().add(new GIOPProcessorFilter());/
> /
> /
> /
> /
> / try {/
> / // Bind server socket and start transport/
> / transport.bind(PORT);/
> / transport.start();/
> /
> /
> / System.out.println("Press <enter> to exit...");/
> / System.in.read();/
> / } finally {/
> / transport.stop();/
> / TransportFactory.getInstance().close();/
> / }/
> / }/
> /
> /
> That's it. So, your work will be just write GIOPProcessorFilter, which
> knows what to do with GIOP message, and don't bother with possible
> packet fragmentation, ByteBuffers or other things.

I like that. But the protocol is a little simple :-) I think a great
test case would be to have an HTTP one, which is more complex as we need
to support http version 0.9, 1.0 and 1.1. I don't see any issues right
now, but would like to make sure it is doable as I suspect your
SmartCodec idea might becomes the de-facto way of build Grizzly Application.





>
> 3) Client part....
>
> / Connection connection = null;/
> / // Create TCP NIO transport/
> / TCPNIOTransport transport =
> TransportFactory.getInstance().createTCPTransport();/
> /
> /
> / // Initialize smart Codec/
> / *SmartCodec smartCodec = new SmartCodec(GIOPMessage.class);*/
> /
> /
> / try {/
> / // start transport/
> / transport.start();/
> /
> /
> / // Connect client to the GIOP server/
> / ConnectFuture future = transport.connect(GIOPServer.HOST,/
> / GIOPServer.PORT);/
> / /
> / connection = future.get(10, TimeUnit.SECONDS);/
> /
> /
> / // Enable standalone mode for this connection/
> / // (don't use Filter chains or other I/O event processors)/
> / connection.setPreferableProcessorSelector(new
> NullProcessorSelector());/
> /
> /
> / // Initialize sample GIOP message/
> / byte[] testMessage = new String("GIOP test").getBytes();/
> / GIOPMessage sentMessage = new GIOPMessage((byte) 1, (byte) 2,/
> / (byte) 0x0F, (byte) 0, testMessage);/
> /
> /
> / // Write message/
> / Future<WriteResult> writeFuture =/
> / connection.write(sentMessage,
> *smartCodec.getEncoder()*);/
> /
> /
> / writeFuture.get(10, TimeUnit.SECONDS);/
> /
> /
> /...................................................................../
> /
> /
> / // Receive result back/
> / Future<ReadResult> readFuture = connection.read(null,/
> / *smartCodec.getDecoder()*);/
> / ReadResult result = readFuture.get(10, TimeUnit.SECONDS);/
> / GIOPMessage reply = (GIOPMessage) result.getMessage();/
> /...................................../
> /
> /
> Here [1] you can find working code of simple GIOP client and GIOP echo
> server.
>
> Smart codec is able to work with complex message types, which have not
> just primitives in it. For example:
> /public class MyMessage {/
> / //*MessageHeader* header;
> /
> / *MessageBody* body;/
> /}/
> /
> /
> /public class MessageHeader {/
> / //private int id;
> /
> / private int seq;/
> /}/
> /
> /
> /public class MessageBody {/
> / private int length;/
> / @Sequence(size=_at_Size(ref="length"))/
> / private byte[] body;/
> /}/
>
>
> If you have some message, or message member, which encoding/decoding you
> want to customize, you can set the custom Transformer, which will be
> responsible for encoding it.
>
> /public class CustomizedMessage {/
> /* *//*_at_Encoder("my.own.header.Encoder")
> */
> /* @Decoder("my.own.header,Decoder")*/
> / //CustomizedHeader header;
> /
> /
> /
> / NonCustomizedBody body;/
> /}/
>
> Will appreciate your feedback!

Looks good, but need a more complex example to make sure it works :-)

A+

-- jeanfrancois



>
> Thanks.
>
> WBR,
> Alexey.
>
>
> [1] https://grizzly.dev.java.net/source/browse/grizzly/branches/2dot0/samples/framework-samples/src/main/java/org/glassfish/grizzly/samples/smart/giop/