[TBD: Insert overview of the world before and after automagic correlation]
A common use case consists of a client that needs to invoke multiple operations against the same service. Each operation depends on the state resulting from the completion of the previous operation. The service needs to associate these invocations with states it maintains internally. That's the basis for the State Exchange protocol.
In the initial invocation, the client sends a request to the service. The service returns a response that includes a state identifier. The state identifier is opaque to the client, however, the client knows to use that state identifier in subsequent invocations that depend on the state of the pervious invocation.
In a subsequent invocation, the client sends a request to the service and includes the state identifier. The service is able to associate this request with thwe state reached by the previous request.
The exact mechanism for carrying the state identifier depends on the underlying transport protocol and the message wire format. This specification provides bindings for SOAP and HTTP.
The protocol requires an initial two-way operation, followed by any combination of two-way and one-way operations.
The service can decide how long to keep an association between the state identifier and any internal state, and how to deal with failure conditions that may result in loss of state. A service should express its ability to maintain state association through its policy.
The service responds with an error if it expects to receive a state identifier and does not find one in the message, or if it cannot associate the state identifier with any known state.
Unless specified otherwise, the client expects to receive the same state identifier in subsequent invocations of the service. The client may detect an error condition if it sends one state identifier and receives another. Unless specified otherwise, the client may conclude that the state identifier is no longer associated with any state if it receives a response that does not include a state identifier.
Although the state identifier is opaque to the client, the client can compare state identifiers for equivalence. Two state identifiers are equivalent if they contain the same set of characters.
Services are encouraged to create unique identifiers for each internal state using globally unique identifiers. In doing so, they prevent accidental association of two unrelated states.
Some interactions involve more than one client or more than one service. These interactions require the clients and services to communicate stateful EPRs.
A stateful EPR is an EPR that contains all the information necessary to invoke a service in association with a particular state. A stateful EPR is essentially an EPR that incorporates a state identifier. For example, when using WS-Addressing, the stateful EPR will include the state identifier as a reference property.
The client obtains the stateful EPR in one of three ways: By composition. From a header or the body of the message. * From the state callback header.
When using WS-Addressing, the client can compose the stateful EPR by combining the service EPR and the state identifier, using the state identifier as a reference property.
All addressing mechanisms support stateful EPRs. However, not all addressing mechanisms allow the client to compose stateful EPRs. For example, when using the HTTP protocol bindings, only the service can construct stateful EPRs.
The service may also send a stateful EPR in a header or the body of the message. The service may send its own stateful EPR, or the stateful EPR of a different service (see Shared States). The state callback header is a special case of that (see State Callback).
There are cases where two or more services share a common state. This non-normative part of the specification provides guidelines for implementing such scenarios.
For example, a process may implement two services that both affect the same process instance (internal state). The client invokes operations on the first service against the same process instance by using one state identifier. The client then needs to invoke operations on the second service against the same process instanace.
The two services use different EPRs, and the client may not be able to deduct one stateful EPR from the other. In fact, it is highly recommended that the two stateful EPRs use different state identifiers. Instead, the first service obtains the stateful EPR of the second service and sends it to the client.
In this case, the first service obtains the stateful EPR of the second service and sends it to the client.
For example, a BPEL process may receive a request on one partnerLink, assign the myRole EPR of another partnerLink to a message and reply with that message. After extracting the EPR from the message, the client is able to invoke the same process instance using the second partnerLink.
To support this pattern we recommend that a BPEL implementation construct a stateful EPR for a partnerLink myRole on or before first use. First use occurs when that partnerLink myRole is assigned to a variable, or communicated in the header of a message by a process instance. Once set, the stateful EPR remains the same until discarded by the process instance.
There are may ways in which services can be combined using stateful message exchanges. A common pattern consists of a two-way exchange between two services acting as peers invoke each other. This pattern is common enough that the State Exchange protocol introduces a specific header to cater for it.
The State Exchange protocol supports this pattern using state callback headers. State callback headers are sent in addition to state identifiers to provide a callback address. They are used to associate two states with each other.
In the initial invocation, the first service constructs a stateful EPR and sends it as a state callback header. The second service returns a response with a state identifier. In a subsequent invocation, the first service uses that state identifier to invoke the second service.
The second service may also follow up with an invocation of the first service using the stateful EPR provided in the state callback header. In this manner, both services can invoke each other within the same interaction.
Both services maintain their own internal states and use separate state identifiers. The state association results from invocations that, regardless of direction, refer to both internal states.
In order to support addressing schemes that do not allow the client to compose a stateful EPR, a service may return a callback state header in lieu of, or in addition to the state identifier. The client may then choose whether to use the state identifier or stateful EPR for subsequent invocations of that service.
TBD: Cleanup
An important characteristic of the State Exchange protocol is that clients and servers must be aware whether the interaction is in fact stateful. Reaching that decision is not always possible, but for the benefit of protocols that allow it, we introduce a fail-fast mechanism.
When the client sends a message to the service that does not require the state identifier or state callback header, it may use the state use header instead. This header informs the service that the client supports state exchange. The client may also force the service to process the header (e.g. using the SOAP mustUnderstand attribute) to guarantee that the service supports state exchange.
When using SOAP, the state identifier is sent in the header state:identifier
and the callback EPR is sent in the header state:callback
. If the message does not contain either header, it may use the state:use
header to indicate support for the State Exchange protocol.
The state:identifier
header is an element of type xsd:string that contains an opaque identifier.
The state:callback
header is an element of type wsa:EndpointReference
that contains a WS-Addressing EPR. It must contain the reference property state:identifier.
The state:use
header is an element of type xsd:boolean
that must contain the value true.
The state:identifier
header must be present in any response message, as long as the service can maintain an association for that state identifier. A response message that does not include the state:identifier header signals to the client that the service no longer accepts that state identifier.
A client can compose the stateful EPR of a service by combining the service EPR with the state:identifier
header, using it as a reference property. When it sends a message to the service, it uses the service EPR and copies the state:identifier element to the header of the SOAP message. In doing so, it fulfills the requirements of both WS-Addressing and State Exchange protocol.
To fail fast is the protocol is not supported, clients are encouraged to use the mustUnderstand attribute to force the service to process state headers. Services are encourage to look for the existence of a state header to determine if the client supports the State Exchange protocol. Additional checking can be done on response messages.
The following table summarizes SOAP faults used by the State Exchange protocol:
state:missingIdentifier | The service expects to receive a state identifier and did not find one in the message. |
state:noSuchState | The state identifier is not associated with any internal state maintained by the service. |
state:missingHeader | The service expects a state exchange and the client did not provide any state header. |
state:invalidCallback | The state:callback header cannot be used as an endpoint reference. |