Google protocol Buffer Codec

Jannick Bitsch jannick at ovja.dk
Thu Jan 7 18:27:01 EST 2010


Hi again :)

Made a quick example of doing the same thing Trustin just demonstrated, by
using the protobuf union type/wrapper trick. Should note that protobuf does
not (and can not be made to) generate any code to provide easy handling for
this approach, so its a bit cumbersome. Okay, to the example, lets say you
want to send the messages Foo and Bar. The trick is to define a "union type"
or a sort of a container that you put your actual message inside:

message Foo{
optional string some_field = 1;
}

message Bar{
optional string some_other_field = 1;
}


message MessageWrapper{
enum Type {FOO = 1; BAR = 2; }
required Type type = 1;

optional Foo foo = 2;
optional Bar bar = 3;
}


So when you want to send a Foo message, you construct the Foo message as
usual, and then wrap it inside a MessageWrapper mesage. You then have to
adhere to the convention, that always
 1) Set just one of the optional fields
 2) Set the Type field to the enum representing that field.

For example to send Foo:

Foo fooMsg =
Foo.newBuilder().
setSomeField("SomeValue").
build();
 MessageWrapper wrapperMsg =
MessageWrapper.newBuilder().
setType(Type.FOO).
setFoo(fooMsg).
build();

someChannel.write(wrapperMsg);

Note: It's important that you always remember to wrap the messages you send,
otherwise you get a very strange behavior.

You then setup your pipeline with a handler to receive this wrapper message:
p.addLast("protobufDecoder", new
ProtobufDecoder(MessageWrapper.getDefaultInstance()));

and in your application specific handler do something like:

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
MessageWrapper wrapperMsg = (MessageWrapper)e.getMessage();
 switch (wrapperMsg.getType()){
 case FOO:
Foo fooMsg = wrapperMsg.getFoo();
//Handle a Foo message
break;
 case BAR:
Bar barMsg = wrapperMsg.getBar();
//Handle a Bar message
break;
 default:
throw new IllegalArgumentException("..... Type: " + wrapperMsg.getType());
 }
 }


Hope this helps. Will see if I can find time to put a complete sample
together.

Regards
Jannick


2010/1/7 "Trustin Lee (이희승)" <trustin at gmail.com>

> Tom,
>
> I would write a custom decoder instead of using ProtobufDecoder in such
> a case; something like the following, which prepends the message type
> and the message length field:
>
> public class MyProtobufDecoder extends FrameDecoder {
>
>  boolean waitingForHeader;
>  int msgType;
>  int msgLength;
>
>  Message prototypeA =
>      MessageA.getDefaultInstance().getDefaultInstanceForType();
>  Message prototypeB =
>      MessageB.getDefaultInstance().getDefaultInstanceForType();
>  Message prototypeC =
>      MessageC.getDefaultInstance().getDefaultInstanceForType();
>
>  @Override
>  protected Object decode(ctx, msg) {
>    ChannelBuffer buf = (ChannelBuffer) msg;
>    if (waitingForHeader) {
>      // Wait until at least 5 bytes are received in the buffer
>      if (buf.readableBytes() < 5) {
>        return null;
>      }
>      msgType = buf.readByte();
>      msgLength = buf.readInt();
>      waitingForHeader = false;
>    }
>
>    if (!waitingForHeader) {
>      ChannelBuffer pbmsg = buf.readBytes(msgLength);
>      Message prototype;
>      switch (msgType) {
>      case 0: prototype = prototypeA; break;
>      case 1: prototype = prototypeB; break;
>      case 2: prototype = prototypeC; break;
>
>      // This is a user defined exception.
>      // Handle this exception in exceptionCaught()
>      // in your terminal handler
>      default: throw new ProtocolViolationException();
>      }
>
>      try {
>        return prototype.newBuilderForType().mergeFrom(
>                    new ChannelBufferInputStream(pbmsg)).build();
>      } finally {
>        waitingForHeader = true;
>      }
>    }
>  }
> }
>
> You will have to learn how to write a decoder eventually to customize
> the protocol to meet your need.  The user guide and the factorial
> example is a good starting point.
>
> However, I would still recommend the solution Jannick provided.
>
> HTH,
> Trustin
>
> ritom wrote:
> > Thanks for very much for the insight. If you do have multiple messages
> how to
> > you handle them in the decoder. In the example looks like everything is
> > based on one object what if you have two message type Foo and Bar instead
> of
> > LocalTimeProtocol alone. Can you please give a example. Thanks a lot in
> > advance.
> >
> >   p.addLast("protobufDecoder", new
> > ProtobufDecoder(LocalTimeProtocol.Locations.getDefaultInstance()));
> >
> >
> > Thingfish wrote:
> >> Hi
> >>
> >> The easiest solution is to wrap all your messages in a 'union type' as
> >> described in this protobuf tutorial:
> >>
> http://code.google.com/intl/da-DK/apis/protocolbuffers/docs/techniques.html#union
> >>
> >> Alternatively you will have to manually prepend some kind of command id
> to
> >> identity the kind of protobuf message being sent, but unlikely to be
> worth
> >> the trouble.
> >>
> >>
> >> Regards
> >> Jannick
> >> <
> http://code.google.com/intl/da-DK/apis/protocolbuffers/docs/techniques.html#union
> >
> >>
> >> 2010/1/2 ritom <ritom at hotmail.com>
> >>
> >>> Can somebody please help me understand the google protobuf support
> within
> >>> Netty.
> >>> In the LocalTimeServerPipelineFactory example we have
> >>>
> >>> p.addLast("protobufDecoder", new
> >>> ProtobufDecoder(LocalTimeProtocol.Locations.getDefaultInstance()));
> >>>
> >>> That would mean we can now receive the Locations message in
> >>> TimeServerHandler.
> >>>
> >>>  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
> {
> >>>        Locations locations = (Locations) e.getMessage();
> >>>
> >>> How would I implement support for multiple incoming message types where
> >>> you
> >>> might be receiving different types of request from the client. Lets say
> >>> you
> >>> are receiving Logon first then BalanceRequest, TransferRequest and so
> on.
> >>> Also server will reply with multiple Message Types depending on the
> >>> request.
> >>> Can somebody please please help.
> >>>
> >>> Tom
> >>> --
> >>> View this message in context:
> >>>
> http://n2.nabble.com/Google-protocol-Buffer-Codec-tp4241485p4241485.html
> >>> Sent from the Netty User Group mailing list archive at Nabble.com.
> >>> _______________________________________________
> >>> netty-users mailing list
> >>> netty-users at lists.jboss.org
> >>> https://lists.jboss.org/mailman/listinfo/netty-users
> >>>
> >> _______________________________________________
> >> netty-users mailing list
> >> netty-users at lists.jboss.org
> >> https://lists.jboss.org/mailman/listinfo/netty-users
> >>
> >>
> >
>
> --
> what we call human nature in actuality is human habit
> http://gleamynode.net/
>
>
>
> _______________________________________________
> netty-users mailing list
> netty-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/netty-users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/netty-users/attachments/20100108/6b7a591e/attachment-0001.html 


More information about the netty-users mailing list