Polymophic messages with Jboss’s Netty and Google’s Protocol Buffers.

First I want to give credit where due to: http://www.indelible.org/ink/protobuf-polymorphism/

I recently restarted working on my client/server architecture for Dunya. I decided to use protobuf to handle message generation since ideally my clients will be open and written in either C++, Java, or [your language here...].

I wanted an Abstract message type that could be extended by more specific types. For more detailed information on how to get this working in protobuf see the link above, or just look at my .proto file below. Now I will show you how to properly setup your pipeline to decode protobuf messages, how to construct and send the polymorphic message, and how to go about handling it in your Channel Handler. This is a great improvement over my previous implementation, because it is now easier to use cross language.
Protobuf definition

package request;

option java_package = "com.dunyaonline.communication.messages.requests";
option java_outer_classname = "AbstractRequestProtos";

message AbstractRequest {
	extensions 100 to 115;
	enum Type {
		NewCharRequest = 0;
		CharListRequest = 1;
	required Type type = 1;

message CharListRequest {
	extend AbstractRequest {
		required CharListRequest request = 100;
	required int32 userid = 1;
	required int32 world = 2;

message NewCharRequest {
        extend AbstractRequest{
		required NewCharRequest request = 101;
	required string name = 1;
	required int32 userid = 2;

Client Message Initialization and Send

public void getCharacterList() {
	AbstractRequestProtos.CharListRequest clr = AbstractRequestProtos.CharListRequest
	AbstractRequest ar = AbstractRequest

public ChannelFuture sendMessage(Object obj) {
		return channel.write(obj);

Server Network Initialization

	private void initNetwork() {
		ChannelFactory factory = new NioServerSocketChannelFactory(

		ServerBootstrap bootstrap = new ServerBootstrap(factory);
		bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
			public ChannelPipeline getPipeline() throws Exception {
				ChannelPipeline pipeline = Channels.pipeline();
				// Decoder
						new ProtobufVarint32FrameDecoder());

						new ProtobufDecoder(
				// Encoder
						new ProtobufVarint32LengthFieldPrepender());
				pipeline.addLast("protobufEncoder", new ProtobufEncoder());
				pipeline.addLast("handler", new ServerMessageHandler());
				return pipeline;

		bootstrap.setOption("child.tcpNoDelay", true);
		bootstrap.setOption("child.keepAlive", true);
		bootstrap.bind(new InetSocketAddress(PORT));


public class ServerMessageHandler extends SimpleChannelHandler {

	private Logger LOGGER = Logger.getLogger(ServerMessageHandler.class);
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
			throws Exception {
		super.messageReceived(ctx, e);
		AbstractRequest r = (AbstractRequest) e.getMessage();
		if(r.getType().getNumber() == AbstractRequest.Type.NewCharRequest_VALUE)
			LOGGER.info(NewCharacterRequest.class.getName() + ": " + e.getMessage());
		}else if(r.getType().getNumber() == AbstractRequest.Type.CharListRequest_VALUE)
			LOGGER.info(CharacterListRequest.class.getName() + ": " + e.getMessage());
                        ByteString str = r.getUnknownFields()
			CharListRequest clr = CharListRequest.parseFrom(str);
                        // Now you have an instance of CharListRequest and can invoke its getters:
                        getPlayerCharacters(clr.getUserid(), clr.getWorld());
			LOGGER.info(ctx.getChannel().getRemoteAddress() + ": " + e.getMessage());

Leave a Comment

You must be logged in to post a comment.

14 Trackbacks \ Pings »