In SwitchYard 0.3, there is the notion of MessageComposers and ContextMappers.

A MessageComposer can compose or decompose a native binding message to/from SwitchYard's canonical message. A MessageComposer does this in threee steps:

Construct a new target message instance.

Copy the content ("body") of the message.

Delegate the header/property mapping to a ContextMapper.

We currently have a SOAPMessageComposer, a CamelMessageComposer, and a HornetQMessageComposer.

A ContextMapper moves native binding message headers and/or properties to/from SwitchYard's canonical message. We currently have a SOAPContextMapper, a CamelContextMapper, and a HornetQContextMapper.

The above are the default implementations, but users can override with their own MessageComposer and/or ContextMapper implmementations by using the <messageComposer/> and <contextMapper/> elements in their <binding.xxx/> section(s) of their switchyard.xml.

This discussion thread is focused on the out-of-the-box behavior of the default ContextMapper implementations we provide in 0.3:

A SOAPContextMapper, when processing an incoming SOAPMessage, takes the mime (in most cases, HTTP) headers from a soap envelope and maps them into the SwitchYard Context as Scope.IN properties, and takes the soap headers from the soap envelope and maps them into the SwitchYard Context as Scope.EXCHANGE properties. When processing an outgoing SOAPMessage, it takes the SwitchYard Scope.OUT Context properties and maps them into mime (in most cases, HTTP) headers, and takes the SwitchYard Scope.EXCHANGE Context properties and maps them into the soap envelope as soap headers.

A CamelContextMapper, when processing an incoming CamelMessage, takes the CamelMessage headers and maps them into the SwitchYard Context as Scope.IN properties, and takes the CamelMessage properties and maps them into the SwitchYardContext as Scope.EXCHANGE properties. When processing an outgoing CamelMessage, it takes the SwitchYard Scope.OUT Context properties and maps them into the CamelMessage as headers, and takes the SwitchYard Scope.EXCHANGE Context properties and maps them into the CamelMessage as properties.

A HornetQContextMapper, when processing an incoming ClientMessage, takes the ClientMessage properties and maps them into the SwitchYardContext as Scope.EXCHANGE properties. When procesing an outgoing ClientMessage, it takes the SwitchYard.EXCHANGE Context properties and maps them into the ClientMessage as properties. There is no concept of "headers" in a HornetQ ClientMessage.

The reasoning of scoping headers as IN and OUT scopes was modeled after the notion of http headers, where you will see some headers specifically useful for http requests, and other headers specifically useful for http responses. In both cases, they are most likely tied to the binding's notion of an incoming message or an outgoing message.

The reasoning of scoping properties as EXCHANGE scope came from the idea that this is most likely application or domain data, and possibly (probably?) useful in the entire processing of the Exchange. An example of this would be a processInstanceId when using the BPM Component.

Is the above behavior what we want by deault? Are there any unwelcome side-effects you can think of? Comments and criticism welcome. Thanks!

Please carefully consider the ramifications WRT "Guaranteed Delivery" and "Once and once only", specifically for transactional transports. The HornetQ scheme sounds like a message will be picked off the HornetQ queue and replaced by a new message. If this happens, and transactions are applied, then if the "bus message" fails it's possible the HornetQ message will not be able to roll back to the sender.

There are times when this is undesirable. I don't have a complete plan for better behavior, but it's often requested that a failure on the bus should result in the original (HornetQ, in this case) transaction should roll back. Do you think we can somehow pull this off?

In my perspective, for the SOAP case, I see both the Transport (HTTP etc.,) headers as well SOAP Envelope headers to be mapped to a single Message. They are relevant only to that SOAP Message. The SOAP Message can be classified as Request or Response.

So all headers from a SOAP Request Message (both Transport and SOAP headers) should be placed in our context as Scope.IN properties and those placed in Scope.OUT will be used to create the SOAP Response Message. If the user would like the Request headers also to be present when the Response is composed, then that can be flagged through configuration and placed in Scope.EXCHANGE. One other distinction is also needed so as to identify what Scope.OUT properties need to become the Response SOAP Headers. Probably for the SOAP case these can be distinguished as two named properties TransportHeader and SoapHeader, each being a bag of its own properties.

Sorry I missed your question before. While I agree with the requirement in principle, I think it's orthogonal to the context mapping question David posed. He's simply asking where data outside of the native transport's message body/payload should be place in our representation of a message. It's interesting that you bring this up, however, because it is related to another feature (Transactional Policy) that we introduced in 0.3. The documentation on that developing feature is here and there's also a quickstart.

cheers,

keith

Rick Wagner wrote:

Please carefully consider the ramifications WRT "Guaranteed Delivery" and "Once and once only", specifically for transactional transports. The HornetQ scheme sounds like a message will be picked off the HornetQ queue and replaced by a new message. If this happens, and transactions are applied, then if the "bus message" fails it's possible the HornetQ message will not be able to roll back to the sender.

There are times when this is undesirable. I don't have a complete plan for better behavior, but it's often requested that a failure on the bus should result in the original (HornetQ, in this case) transaction should roll back. Do you think we can somehow pull this off?

I don't think there's an absolute right or wrong here, but I think SOAP Headers should be scoped to the message and not the exchange. While there are some examples of headers which apply to both the input and the output message (e.g correlation/conversation identifier), I believe it is more common for headers to apply to a specific message (e.g. timestamp, security info, message identifier, etc.). The nice thing here is that the composer framework is more than capable of accommodating this by introducing a custom composer or (as an enhancement) specific configuration about which headers should be mapped to Exchange scope. IMO, the default should be everything maps to message scope unless specifically configured to do otherwise.