In AMQP 0-10 message content was essentially always treated as raw data, with the content-type indicating how those bytes were to be interpreted. For map- and list- messages we used a content-type of amqp/map and amqp/list respectively.

In AMQP 1.0, though you can of course still send raw data (as a Data section) with a content-type specified in the properties, the preferred method of sending maps and lists is through an AmqpValue section with the type encoded in the bytes making up that section.

I've been working on support for map- and list- messages over 1.0 through the c++ qpid::messaging API and have an approach ready for some feedback[1].

Over 0-10, the approach used was to have encode/decode functions that work with a Variant::Map or Variant::List. The application was responsible for encoding outgoing messages before sending them and checking the content-type on received messages and decoding them if appropriate.

Now that the content-type cannot be relied on to indicate the type of the message (indeed the specification encourages it *not* to be used, relying only on the type encoding in the AmqpValue section), a different approach is necessary.

I've added a method to Message to get the content as a Variant. This can be used for a whole range of different types of data including binary or maps and lists. All the existing methods for accessing content remain of course and in the case of structured data, they will return the raw bytes.

With this approach, the application doesn't directly encode or decode the data itself, but simply reads or manipulates the Variant typed content. E.g instead of:

  Message message;
  Variant::Map content;
  content["a"] = "bcd";
  encode(content, message);
  sender.send(message);

a map message would be sent like this:

  Message message;
  message.content() = Variant::Map();
  message.content()["a"] = "bcd";
  sender.send(message);

and instead of:

  Message message = receiver.receive();
  if (message.getContentType() == "amqp/map") {
     Variant::Map content;
     decode(message, content);
     //process content:
     std::string x = content["a"];    
  } else {
     //handle unexpected format
  }

receiving a map message would look like this:

  Message message = receiver.receive();
  if (message.content().getType() == VAR_MAP) {
     //process content:
     std::string x = message.content().asMap()["a"];  
  } else {
     //handle unexpected format
  }

The old approach will of course continue to work for 0-10 without modification, but in order to support the same pattern over both protocols I have modified the 0-10 path also. For sending, if you don't touch Message::content() then it will behave just like it did before. For receiving, map- and list- messages will by default be decoded automatically when fetched (and made available via Message::content()). This can if desired be disabled via a connection option; it doesn't break anything but if your application already explicitly tests the content type and decodes then its doing redundant work.

For 1.0 you can also of course continue to send raw bytes with an associated content-type if desired as well. I haven't actually exposed 1.0 based encode and decode routines for this purpose though.

Any feedback on this as an approach is welcome. I'd be especially excited to hear from anyone who thinks they might want to send AMQP 1.0 encoded structured content. A patch is available for those who want to see the gory details[1].

--Gordon.

[1] https://reviews.apache.org/r/13328/

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to