@Override
  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {

    Object m = e.getMessage();
    if (!(m instanceof ChannelBuffer)) {
      ctx.sendUpstream(e);
      return;
    }

    ChannelBuffer input = (ChannelBuffer) m;
    if (!input.readable()) {
      return;
    }

    ChannelBuffer cumulation = cumulation(ctx);
    if (cumulation.readable()) {
      cumulation.discardReadBytes();
      cumulation.writeBytes(input);
      callDecode(ctx, e.getChannel(), cumulation, e.getRemoteAddress());
    } else {
      callDecode(ctx, e.getChannel(), input, e.getRemoteAddress());
      if (input.readable()) {
        cumulation.writeBytes(input);
      }
    }
  }
  @Override
  protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) {
    try {
      // Header and length
      if (buffer.readableBytes() < 6) {
        return null;
      }

      // New byte array for length
      byte[] Length = buffer.readBytes(4).array();

      if (Length[0] == 60) {
        buffer.discardReadBytes();

        String policy =
            "<?xml version=\"1.0\"?>\r\n"
                + "<!DOCTYPE cross-domain-policy SYSTEM \"/xml/dtds/cross-domain-policy.dtd\">\r\n"
                + "<cross-domain-policy>\r\n"
                + "<allow-access-from domain=\"*\" to-ports=\"*\" />\r\n"
                + "</cross-domain-policy>\0";

        channel.write(policy);
      } else {
        // Retrieve length in integer form
        Integer newLength = BitConverter.toInt32(Length, 0);

        // New channel buffer to read the packet from given length
        ChannelBuffer msg = buffer.readBytes(newLength);

        // Turn to byte buffer for header
        Short id = ByteBuffer.wrap(msg.readBytes(2).array()).asShortBuffer().get();

        return new ClientMessage(id, msg);
      }
    } catch (Exception e) {
    }
    return null;
  }