Enterprise Integration Patterns
Conversation Patterns
Conversation Patterns
Introduction to Describing ConversationsConversation Patterns » Describing Conversations

To participate in a structured conversation, participants need to understand what is required of them, and what they can expect from their conversation partners. For example, a service consumer needs to know that it can initiate a conversation any time by sending a message. It also needs to know whether it can safely resend a request message, and whether it can expect exactly one response message or whether it has to be prepared to deal with duplicate response messages. The service provider in turn must be able to receive a request message at any time and be prepared to process it.

A conversation policy gives a precise description of all legal message exchanges that make up a specific type of conversation. The policy establishes a contract between conversation participants, which they are expected to abide by.

A conversation policy defines the following elements:

If an instance of a conversation fulfills the rules established by a conversation policy, we call that conversation legal with regards to that policy. Most conversation policies allow many legal instances. For example, the conversation to setup a meeting doesn't require a particular order among the meeting reminder messages to the participants, making any interaction that sends messages to all meeting participants in any order legal.

A Simple Conversation

Let's consider a simple purchasing scenario, which consists of the participants Buyer and Supplier. They exchange the message types Order to place an order, Shipment Notice to indicate the ordered goods have been shipped, Invoice, and Payment. The protocol for the conversation Purchase Transaction specifies that the Supplier sends an Invoice only after receiving an Order message from the Buyer. Every Invoice message must be followed by a Payment from the Buyer, who in turn must be assured that the Order ultimately leads to a Shipment Notice.

However, the conversation policy may not specify an order between the Shipment Notice and Invoice messages, allowing the supplier to send these messages in either order, e.g. the Supplier could invoice before the Shipment Notice. When the Buyer has to follow the Invoice with a Payment will usually be specified in the terms and conditions. If the Payment is not received, the Supplier can send a Reminder and possibly a Request for payment. The conversation policy can also define whether the Buyer is allowed to send a Payment before the Invoice is sent, e.g. to make a prepayment or down-payment. One can quickly see that a relatively simple conversation has to deal with a variety of conditions.

For now we assume that a Payment follows an Invoice, but that Invoice and Shipment Notice are independent. We also omit error conditions, such as a missing payment. The following diagram formulates these constraints as a simple process on the right-hand side. The process diagram, which intentionally does not use any standard notation, contains activity elements indicating sending a message to or receiving a message from the conversation partner. The process begins by receiving an Order message, followed by two parallel execution streams, one of which sends the Shipment Notice and one consisting of sending an Invoice and receiving a Payment. The process only shows the activities relevant to the conversation and omits steps like actually shipping the goods, processing payments, etc.

The left side of the diagram depicts all legal conversation instances of this policy.

Three Legal Instances of a simple Conversation Policy

The process defines the protocol, i.e. the valid sequences in which messages can be sent and received. The supplier's implementation may be more strict than the protocol allows, e.g. the actual implementation may be hard-wired to always send the Invoice message before the Shipment Notice. Nevertheless, the buyer has to be prepared to receive the messages in either order, because the published conversation policy, which is the contract between the participants, allows this. The supplier thus reserves the right to change its implementation in the future thanks to the separation of interface and implementation and the low coupling specified in the contract. The relationship between the declared conversation policy and the actual supplier-side implementation mimics the relationship between a service interface and the service implementation: Service consumers have to abide by the rules of the service interface, not a specific implementation.

Robustness Principle (Postel's Law)

One of the most widely used and robust protocols is TCP - The Transmission Control Protocol that is part of the TCP/IP stack, which forms the basis for pretty much all Internet traffic. When editing the TCP Specification [Transmission Control Protocol], Jon Postels specified the Robustness Principle:

TCP implementations should follow a general principle of robustness: be conservative in what you do, be liberal in what you accept from others.

In our example, the robustness principle could mean that the Supplier can accept Payment messages before the Invoice message was sent, even though the conversation policy does not allow this.

Mapping the Conversation Policy to the Participants

Each conversation participant projects the conversation policy onto its own viewpoint of the conversation. For example, the buyer’s view if the above conversation prescribes that it has to initiate the conversation by sending an Order message, and has to be ready to receive two messages in either order next. When it receives the Invoice message, it has to reply with a Payment message.


Describing Conversations

Conversation protocols can fundamentally be described statically or dynamically. Static descriptions are defined and known to the participants a priori, i.e. before they engage in the conversation. This allows participants to understand the rules of engagement beforehand and also enables code generation to automatically implement participant-side workflow that is guaranteed to be in line with the conversation policy. Once, the policy is defined, though, it cannot easily be changed.

Dynamic protocol definitions only exist once the conversation has started. This implies that at least one participant knows up-front how to initiate the conversation. Subsequently, a conversation participant can describe allowed next steps as part of the message being sent to other participants. Naturally, this approach provides the loosest coupling, but it does not support code generation or static validations.

Conversation protocols can be described using the following methods:

Error States

When looking at conversations, we often look at the "happy path", i.e. the sequence or sequences of steps that accomplish the primary objective of the conversation. As with all activities, naturally many things can go wrong: expected responses are not received, have the wrong format, or come in the wrong order. Also, the engine executing the process behind the conversation might crash and have to pick up at a later place.

Composing Conversations

Many conversations have to deal with multiple aspects at once: they may have to discover a service provider, authenticate to it, then initiate a conversation, while renewing a Lease to keep using resources. It is helpful to consider the elements of such conversations separately. The conversational elements can be composed in multiple ways:

Conversations at multiple levels

Different layers of the communication can use different conversation protocols. For example, a TCP stack implements a reliable protocol over asynchronous IP packets by using Request-Response with Retry while an application might hold a Asynchronous Request-Response conversation on top of TCP, e.g. by using two separate HTTP connections. Lastly, the client application might not actually be able to process response messages asynchronously, but rather uses Polling to obtain the response from the interface layer (see figure).

Different Protocols between Different Layers

This (quite realistic) scenario employs three different conversations that all work together to move data between A and B. It is therefore essential that whenever we talk about conversation protocols that we state the context, i.e. the communications layer, that we refer to. By default, we assume that the conversation occurs over a common messaging system that is implemented using common protocols such as HTTP or that is abstracted behind common APIs such as JMS, MSMQ or the like. These APIs or base protocols define what the application layer understands as "message" and therefore defines the context of the conversations. In this example, we would consider the conversation an Asynchronous Request-Response unless otherwise stated.