Using the HTTP Inbound Adapter
This chapter describes the default behavior of the Ensemble HTTP inbound adapter (EnsLib.HTTP.InboundAdapterOpens in a new tab) and describes how to use this adapter in your productions. It discusses the following topics:
Ensemble also provides specialized business service classes that use this adapter, and one of those might be suitable for your needs. If so, no programming would be needed. See “Connectivity Options” in Introducing Ensemble.
Overall Behavior
EnsLib.HTTP.InboundAdapterOpens in a new tab is the Ensemble HTTP listener for custom port listening, XML listening, and/or raw HTML handling. You use this adapter in cases when you prefer to listen on a private port rather than using a CSP page (which uses the standard web server to handle HTTP requests).
First, the class provides runtime settings that you use to specify items like the following:
-
A local port, where the adapter will listen for input
-
A list of IP addresses from which the adapter will accept input (if you want to restrict the possible sources)
-
Settings that specify whether to use the character set given in the inbound request, and if not, what other character set to use
The inbound HTTP adapter listens to a port on the local machine, reads the input, and sends the input as a stream to the associated business service. The business service, which you create and configure, uses this stream and communicates with the rest of the production. The following figure shows the overall flow:
In more detail:
-
The adapter receives an HTTP message and opens a TCP connection. (HTTP is a format of header and body data that is sent over a TCP connection.)
-
When the adapter connects, it executes its OnConnected() method, which first determines the character set to use. By default, it uses the character set specified in the inbound HTTP request. For details, however, see “Specifying the Character Set to Use.”
-
The adapter chooses the appropriate translation table for the character set.
-
The adapter reads the body of the input, translates it, and places it into a new stream object.
-
If the adapter is using a non-binary character set, the stream is of type %GlobalCharacterStreamOpens in a new tab.
-
If the adapter is using a binary character set, the stream is of type %GlobalBinaryStreamOpens in a new tab.
The adapter also extracts each HTTP header and adds that header to the Attributes property of the stream; this property is a multidimensional array, as discussed later.
Also, if the URL includes form parameters, these are passed as follows:
-
If the HTTP request is a GET request, the adapter puts them into the Attributes array under the "Params" subscript.
-
If the HTTP request is a POST request, then the form variables are written into the request body.
-
-
The adapter then calls the internal ProcessInput() method of the business service class, passing the stream as an input argument.
-
The internal ProcessInput() method of the business service class executes. This method performs basic Ensemble tasks such as maintaining internal information as needed by all business services. You do not customize or override this method, which your business service class inherits.
-
The ProcessInput() method then calls your custom OnProcessInput() method, passing the stream object as input. The requirements for this method are described later in “Implementing the OnProcessInput() Method.”
-
If ProcessInput() or OnProcessInput() returns an error, Ensemble invokes the OnErrorStream() method of the business service.
The response message follows the same path, in reverse.
Creating a Business Service to Use the HTTP Inbound Adapter
To use this adapter in your production, create a new business service class as described here. Later, add it to your production and configure it. You must also create appropriate message classes, if none yet exist. See “Defining Ensemble Messages” in Developing Ensemble Productions.
The following list describes the basic requirements of the business service class:
-
Your business service class should extend Ens.BusinessServiceOpens in a new tab.
-
In your class, the ADAPTER parameter should equal EnsLib.HTTP.InboundAdapterOpens in a new tab.
-
If you need to parse form variables from an HTTP POST request, implement the OnInit() callback method as follows:
Method OnInit() As %Status { Set ..Adapter.ParseBodyFormVars=1 Quit 1 }
This step is not necessary to parse the form variables from a GET request; these are automatically parsed into the Attributes property as discussed later in this chapter.
-
Your class should implement the OnProcessInput() method, as described in “Implementing the OnProcessInput() Method.”
-
Your class can implement the OnErrorStream() method. See “Implementing the OnErrorStream() Method.”
-
For other options and general information, see “Defining a Business Service Class” in Developing Ensemble Productions.
The following example shows the overall structure of your business service class. The details of the OnProcessInput() method depend on the character set that the adapter is using. If the adapter is using a non-binary character set, the general structure should be as follows:
Class EHTTP.NewService1 Extends Ens.BusinessService
{
Parameter ADAPTER = "EnsLib.HTTP.InboundAdapter";
Method OnProcessInput(pInput As %GlobalCharacterStream, pOutput As %RegisteredObject) As %Status
{
set tsc=$$$OK
//your code here
Quit tsc
}
}
Or, if the adapter is using a binary character set, the OnProcessInput() method should be as follows instead:
Method OnProcessInput(pInput As %GlobalBinaryStream, pOutput As %RegisteredObject) As %Status
{
set tsc=$$$OK
//your code here
Quit tsc
}
Studio provides a wizard that you can use to create a business service stub similar to the preceding. To access this wizard, click File —> New and then click the Production tab. Then click Business Service and click OK. Note that the wizard provides a generic input argument. If you use the wizard, InterSystems recommends that you edit the method signature to use the specific input argument that you need; the input argument type should be %GlobalCharacterStreamOpens in a new tab or %GlobalBinaryStreamOpens in a new tab.
Implementing the OnProcessInput() Method
Within your custom business service class, the signature of your OnProcessInput() method depends on the character set that the adapter is using:
-
If the adapter is using a non-binary character set, the signature should be as follows:
Method OnProcessInput(pInput As %GlobalCharacterStream, pOutput As %RegisteredObject) As %Status
-
If the adapter is using a binary character set, the signature should be as follows:
Method OnProcessInput(pInput As %GlobalBinaryStream, pOutput As %RegisteredObject) As %Status
Here pInput is the input that the adapter will send to this business service. Also, pOutput is the generic output argument required in the method signature.
The OnProcessInput() method should do some or all of the following:
-
Examine the input object and extract the needed data from it. See “Using the HTTP Request,” later in this chapter.
-
Create an instance of the request message, which will be the message that your business service sends.
For information on creating message classes, see “Defining Ensemble Messages” in Developing Ensemble Productions.
-
For the request message, set its properties as appropriate, using values obtained from the input stream.
If the attribute Content-Type is specified in the Attributes property, by default, that is used as the Content-Type of the request message. If Content-Type is not specified in the Attributes property, by default, the Content-Type of the request message is set to "text/html". If these defaults are not appropriate, be sure to set this attribute. For example, the following code checks the value of the attribute Content-Type of the input stream and uses "text/xml" if the value is missing:
Set outputContentType=$GET(pInput.Attributes("Content-Type"),"text/xml")
-
Call a suitable method of the business service to send the request to some destination within the production. Specifically, call SendRequestSync(), SendRequestAsync(), or (less common) SendDeferredResponse(). For details, see “Sending Request Messages” in Developing Ensemble Productions
Each of these methods returns a status (specifically, an instance of %StatusOpens in a new tab).
-
Optionally check the status of the previous action and act upon it.
-
Optionally examine the response message that your business service has received and act upon it.
-
Make sure that you set the output argument (pOutput). This step is required.
-
Return an appropriate status. This step is required.
The following shows a simple example:
Method OnProcessInput(pInput As %GlobalCharacterStream, Output pOutput As %RegisteredObject) As %Status
{
//get contents of inbound stream
//in this case, the stream contains a single value: a patient ID
Set id=pInput.Read(,.tSC)
//make sure Read went OK
If $$$ISERR(tSC) do $System.Status.DisplayError(tSC)
//create request object to send
Set tRequest=##class(EHTTP.Request.Patient).%New()
Set tRequest.patientID=id
//send to lookup process
Set tSC=..SendRequestSync("EHTTP.LookupProcess",tRequest,.tResponse)
//define output for OnProcessInput
Set pOutput=tResponse
Quit tSC
}
Implementing the OnErrorStream() Method
If the ProcessInput() or OnProcessInput() method of your business service returns an error, Ensemble invokes the OnErrorStream() method of the business service. You can implement this method to contain any desired error handling. The method should accept a status code as input and should return the desired output stream.
Using the HTTP Request
Within OnProcessInput(), the HTTP request is available as pInput, which is an instance of %GlobalCharacterStreamOpens in a new tab or %GlobalBinaryStreamOpens in a new tab, depending on your implementation. The following figure illustrates how this instance represents the HTTP request:
The body of the request is written to the pInput stream. For information on working with streams, see the Caché documentation, for example, the chapter “Defining and Using Stream Properties” in Using Caché Objects.
Additional data is available in the Attributes property of the pInput stream, as discussed in the following subsection. This includes the HTTP headers. If the request was a GET request, it also includes any form variables (URL parameters).
If the request was a POST request, then the form variables are available in the body.
About the Attributes Array
The Attributes property of the pInput stream is a multidimensional array that carries the following data:
Node | Contents |
---|---|
Attributes(http_header_name) Where http_header_name is the header name in lowercase, for example, "content-length" | Value of the given HTTP header |
Attributes("Params",form_variable_name,n) | Value of the nth instance of the given URL form variable (if the HTTP request was a GET request). |
Attributes("URL") | Complete URL of the HTTP request |
So you can retrieve a header value as follows:
set contentlength = pInput.Attributes("content-length")
Or, to retrieve a URL form variable (for a GET request):
set pResponse.MessageRequestTimeStamp = pInput.Attributes("Params","REQUESTTIMESTAMP",1)
Adding and Configuring the Business Service
To add your business service to an Ensemble production, use the Management Portal to do the following:
-
Add an instance of your custom business service class to the Ensemble production.
-
Configure the adapter so that it can receive input. Specifically:
-
Specify the port on which the adapter will listen. To do so, specify the Port setting.
-
Optionally specify the IP addresses from which the adapter will accept input, if you want to limit the sources with which the adapter communicates.
-
Optionally specify the character set of the input data.
-
-
Enable the business service.
-
Run the production.
Specifying the Sources of HTTP Requests
You can configure the inbound HTTP adapter to recognize sources of HTTP requests in two different ways:
-
You can permit HTTP requests from any server. This is the default.
-
You can permit HTTP requests from a list of specific servers (optionally with specific ports).
To do so, specify the Allowed IP Addresses setting. See “Reference for Settings.”
Specifying the Character Set to Use
When the EnsLib.HTTP.InboundAdapterOpens in a new tab receives input, it translates the characters in that input according to a translation table. To determine which translation table to use, the adapter first determines which character set the input uses.
In general, the HTTP Content-Type header of the input indicates which character set that request uses. By default, the adapter uses that character set.
However, you can control which character set the adapter uses, by using the following runtime settings:
See “Reference for Settings.”
For background information on character translation in Caché, see “Localization Support” in the Caché Programming Orientation Guide.