Developer

HTTP Conversation

An HTTP conversation is created by HttpConversationManager and is considered to be a single HTTP request/response that can be interrupted by a series of additional requests used to prepare the original. A typical example is an OAuth2-based scenario where a request to a given resource must be preceded by a series of authorization requests before the original can be sent.

Preparing the Conversation

Prepare the HttpConversationManager by instantiating a new object from this type. You can then add headers and parameters, setters for flow listener, response detector, number of maximum restarts, listeners, which can all be invoked. After calling the start() method the conversation begins and further modifications are not allowed.

Request and response listeners:

A listener-based pattern is used for both sending and receiving (IRequestListener and IResponseListener). The response listener is mandatory. The request listener is optional, which means the user is not required to inject additional headers or a body. By default, a conversation is configured with the HTTP GET method.

This example posts binary data using a stream written in the request listener. The binary response is read as a stream in the response listener.

Like filters, these listeners get an event object through which the context (different properties of the request and the response), can be accessed and altered. The request filter is the correct place to write the request body that is supported by the TransmitEvent that provides the stream or writer used, depending on whether binary or textual data is sent.

Specific filters in the com.sap.smp.client.httpc.utils package provide additional services. For example:
  • BackgroundThreadCheckerRequestFilter prevents conversations from running within the main thread.
  • MultipartRequestFacade and MultipartResponseFacade abstract filter classes help support multi-part HTTP messages.
See the API documentation for details about how to use these filters.

Starting a Conversation

After preparation, start a conversation with this call:
conversation.start(); 

The conversation flow

Calling start() triggers these actions in the general conversation flow:
  1. Request filters execute pre-sending actions: authentication, authorization, preliminary request header and parameter processing, and so on. If the conversation determines that the request cannot be fulfilled, filters can cancel the request. The filters might also execute a number of additional HTTP request/response cycles to prepare the original request: this is typical when authentication is required beforehand.
  2. The IRequestListener supplied to the IHttpConversation object finalizes the request, which produces the final set of request headers and the request body.
  3. (Optional) Configured detectors detect responses.
  4. Response filters perform response post-processing before handing it to the response listener supplied to the IHttpConversation object. These filters can cancel processing and restart the entire flow if required.
  5. The IResponseListener supplied to the IHttpConversation object processes the response.

The above flow is submitted as a single continuous processing unit to the executor defined by setExecutor(Executor) on the manager. The client application is notified of flow-related events, such as cancellations, errors, or completion, through the IConversationFlowListener interface. You can set a default flow listener for the manager, which can be overridden by flow listener implementations for each conversation instance. For convenience, an empty flow listener implementation is included, its subclasses can selectively override the required event handler methods.

Contexts

During execution, all filters and listeners have access to two important instances of IContext that include state information that can be preserved and exchanged:
  • Manager context The scope of this context is bounded by the lifetime of a single conversation manager instance. It allows parameters that might be required by subsequent requests to be stored and retrieved. These parameters typically include audit-, tracing-, and authentication/authorization-related information.
  • Conversation context The scope of this context is limited to a single HttpConversation. It allows filters and listeners to communicate with each other within the boundaries of a single request/response exchange.

Both contexts have a name taken from HttpConversationManager.getName() and IHttpConversation#getName() respectively. These names need not be unique and are used only for identification. Clients of this library can name managers and conversations to categorize certain network interactions. For example, an application can give similar names to all conversations that are executed from a particular screen to identify the most appropriate UI location in which to display results.

Filters and listeners can store and share information in a state map. The domain argument is passed to getStateMap(String, boolean) to keep information separate in the context. This allows filters that support different use cases (and have been configured using multiple iManagerConfigurator objects), to store their state information separately.

Any data stored in this context is lost after garbage collection of the HttpConversationManager to which it belongs.

Flow Cancellation

Cancellation can occur at any point in the flow, including during request, sending, or response processing. Different events from different sources can trigger cancellation that causes the flow to stop and a CancellationEvent to be propagated to the corresponding callback of the flow listener:
  • External cancellation The conversation flow can be canceled by invoking the cancel() method on the conversation instance whose flow has already started. The filters and listeners can monitor using the event.isCancelledExternally() method, and it is a good practice to inspect the return value of this method and return if it signals true, especially for implementations performing potentially long-running operations. The CancellationEvent with a null result is propagated to the flow listener’s onExternalCancellation() callback method.
  • Cancellation by filters or request listener
    • If a filter returns a non-null object from its filter() method (except for the special RESTART_SIGNAL returned by a response filter). The propagated CancellationEvent contains the non-null object returned from the filter.
    • If a response filter returns the RESTART_SIGNAL while the maximum restarts has already been reached. The propagated CancellationEvent contains the RESTART_SIGNAL.
    • If a request listener returns a non-null object from one of its callback methods. The propagated CancellationEvent contains the non-null object returned from the listener.