Creating Web Services and Web Clients in Caché
Adding and Using Custom Header Elements
[Back] [Next]
   
Server:docs2
Instance:LATEST
User:UnknownUser
 
-
Go to:
Search:    

This chapter describes how to add and use custom SOAP header elements.

This chapter discusses the following:
For information on adding header elements when faults occur, see the chapter SOAP Fault Handling,” earlier in this book.
A later chapter discusses WS-Addressing header elements. For information on WS-Security header elements, see Securing Caché Web Services.
Introduction to SOAP Header Elements in Caché
A SOAP message can include a header (the <Header> element), which contains a set of header elements. For example:
<SOAP-ENV:Envelope>
   <SOAP-ENV:Header>
      <MyHeaderElement>
         <Subelement1>abc</Subelement1>
         <Subelement2>def</Subelement2>
      </MyHeaderElement>
   </SOAP-ENV:Header>
   <SOAP-ENV:Body>
...
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Informally, each header element is often referred to as a “header.” This is not strictly accurate, because the message itself can contain at most one header, which is always <Header>, with an appropriate namespace prefix. The header can contain WS-Security header elements, WS-Addressing header elements, and your own custom header elements.
A header element carries additional information for possible use by the web service or web client that receives the SOAP message. In the example shown here, this information is carried within XML elements. A header element can also include XML attributes, although none are shown in the previous example. The SOAP standard specifies three standard attributes (mustUnderstand, actor, and encodingStyle) to indicate how a recipient should process the SOAP message.
How Caché Represents SOAP Headers
Caché represents each header element as an instance of %SOAP.Header or one of its subclasses. %SOAP.Header is an XML-enabled class with properties that correspond to the standard header element attributes (mustUnderstand, actor, and encodingStyle).
Caché provides specialized subclasses of %SOAP.Header for use with WS-Addressing and WS-Security. To represent custom header elements, you create your own subclasses of %SOAP.Header.
When a Caché web service or client receives a SOAP message, it imports and processes the message. During this step, if the message contains a header with custom header elements, Caché compares the header elements to the list of supported header elements (discussed in the next subsection).
Then the service or client creates an instance of each applicable header element class, inserts those into an array, and places that array in its own HeadersIn property:
To use these header elements, your Caché web service or client can access the HeadersIn property. If the SOAP message did not include a <Header> element, the Count() of the HeadersIn property is 0.
Similarly, before your Caché web service or client sends a SOAP message, it must update the HeadersOut property so that it contains any custom elements you want to include in the outbound message. If the HeadersOut Count() is 0, the outbound SOAP message does not include a <Header> element.
For custom header elements, you always use the HeadersIn and HeadersOut properties.
The details are different for other (non-custom) header elements:
Supported Header Elements
Caché web services and clients automatically support WS-Addressing and WS-Security headers, but do not automatically support other headers.
To specify the supported header elements in a Caché web service or client, you add an XData block to the class and specify the class parameter USECLASSNAMESPACES. The XData block lists the supported elements. The class parameter causes the WSDL to include the applicable types. See Specifying the Supported Header Elements.”
Header Elements and the WSDL
The WSDL for a web service advertises the header elements supported by that web service and permitted by web clients that communicate with that web service.
For a Caché web service, the generated WSDL might not include information about the SOAP header elements:
Note that the W3C specifications do not require a web service to provide a generated WSDL.
Required Header Elements
If a given header element specifies mustUnderstand=1, the element is considered mandatory, and the recipient must support it. The recipient cannot process the message unless it recognizes all mandatory header element.
Following the SOAP standard, Caché rejects SOAP messages that contain required but unsupported header elements. Specifically, if Caché web service or client receives a message that contains a header element that includes mustUnderstand=1, and if that service or client does not support that header element, the service or client issues a SOAP fault and then ignores the message.
Defining Custom Header Elements
If you use the SOAP Wizard to create a Caché web service or web client based on a given WSDL, Caché generates classes to represent any header elements as needed.
If you create a web service or client manually, you must manually define classes to represent any custom header elements. To do so:
  1. For each custom header element, create a subclass of %SOAP.Header.
  2. Specify the NAMESPACE parameter to indicate the namespace of the header element.
  3. Specify the XMLNAME parameter to indicate the name of the header element.
  4. In the subclass, define properties to contain the header information you need. By default, your properties are projected to elements within your <Header> element.
  5. Optionally specify the XMLFORMAT parameter, which controls the format of this header element. By default, the header elements are always in literal format (rather than SOAP-encoded).
For example:
Class Scenario1.MyHeaderElement Extends %SOAP.Header
{

Parameter NAMESPACE = "http://www.myheaders.org";

Parameter XMLNAME = "MyHeader";

Property Subelement1 As %String;

Property Subelement2 As %String;

}
This header element appears as follows within a SOAP message:
<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope [parts omitted]>
  <SOAP-ENV:Header>
    <MyHeader xmlns="http://www.myheaders.org"
                     xmlns:hdr="http://www.myheaders.org">
      <Subelement1>abc</Subelement1>
      <Subelement2>def</Subelement2>
    </MyHeader>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body>
   [omitted]
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
For details on customizing the XML projection of any given object class, see the book Projecting Objects to XML.
For information on the SOAP Wizard, see Using the SOAP Wizard.”
Adding a Custom Header Element to a SOAP Message
To add custom header elements to a SOAP message (from either the web service or the web client), do the following before sending the SOAP message.
  1. Create an instance of your header object.
  2. Set the properties of that object as appropriate, optionally including the actor and mustUnderstand properties.
  3. Add the new header to the outbound header array, the HeadersOut property. This property is an array with the usual array interface (for example, the SetAt(), Count(), and GetAt() methods).
Note:
If you perform these steps in a utility method, note that the method must be an instance method and must be a member of an instantiable class (not an abstract class, for example).
Then within your web service or client class, you could have a utility method that adds a header element:
Method AddMyHeaderElement(mustUnderstand=0)
{
    Set h=##class(MyHeaderElement).%New()
    Set h.Subelement1 = "abc"
    Set h.Subelement2 = "def"
    If mustUnderstand {Set h.mustUnderstand=1}
    Do ..HeadersOut.SetAt(h,"MyHeaderElement")
}
Finally, you could call this utility method from each web method where you wanted to use it. For example:
/// Divide arg1 by arg2 and return the result
Method Divide(arg1 As %Numeric, arg2 As %Numeric) As %Numeric [ WebMethod ]
{
    //main method code here
    //...

    do ..AddMyHeaderElement()

    Quit ans
}
When you invoke this web method, the header is added to the SOAP response.
Specifying Supported Header Elements
Caché web services and clients automatically support WS-Addressing and WS-Security header elements, but do not automatically support other header elements.
To specify the header elements supported by a Caché web service or web client, do the following:
Specifying the Supported Header Elements in an XData Block
If you use the SOAP Wizard to create a Caché web service or web client based on a given WSDL, Caché generates an XData block in that class to represent any header elements supported in its SOAP messages. (For information on the SOAP Wizard, see Using the SOAP Wizard.”)
If you create a web service or client manually, you must manually specify this XData block.
The following is a simple example:
XData NewXData1
{
<parameters xmlns="http://www.intersystems.com/configuration">
   <request>
      <header name="ServiceHeader" class="NewHeaders.MyCustomHeader"/> 
   </request>
   <response>
      <header name="ExpectedClientHeader" class="NewHeaders.MyCustomHeader"/> 
   </response>
</parameters>
}
Details
The requirements for this XData block are as follows:
Inheritance of Custom Headers
If you create a subclass of this web service, that subclass inherits the header information that is not specific to a method — the header information contained in the <request> or <response> elements that are direct child elements of <parameters>. This is true even if SOAPMETHODINHERITANCE is 0.
Examples
Another example is as follows:
XData service
{
<parameters xmlns="http://www.intersystems.com/configuration">
  <response>
    <header name="Header2" class="User.Header4" alias="Header4"/>
    <header name="Header3" class="User.Header3"/>
  </response>
  <method name="echoBase64">
    <request>
      <header name="Header2" class="User.Header4" alias="Header4"/>
      <Action>http://soapinterop.org/Round2Base.Service.echoBase64Request</Action>
    </request>
    <response>
      <header name="Header2" class="User.Header2" alias="Header2"/>
      <header name="IposTransportHeader" class="ipos.IposTransportHeader"/>
      <Action>http://soapinterop.org/Round2Base.Service.echoBase64Result</Action>
    </response>
  </method>
  <method name="echoString">
    <request>
      <Action>http://soapinterop.org/Round2Base.Service.echoStringRequest</Action>
    </request>
    <response>
      <Action>http://soapinterop.org/Round2Base.Service.echoStringAnswer</Action>
    </response>
  </method>
</parameters>
}
Specifying the Supported Header Elements in the SOAPHEADERS Parameter
The older way to specify supported header elements is to include the SOAPHEADERS parameter in the web service or web client class.
This parameter must equal a comma-separated list of header specifications. Each header specification has the following form:
headerName:headerPackage.headerClass
Where headerName is the element name of the supported header and headerPackage.headerClass is the complete package and class name of a class that represents that header. For example:
Parameter SOAPHEADERS = "MyHeaderElement:Scenario1Client.MyHeaderElement" 
This list identifies all headers supported in the SOAP requests to this web service or client and indicates the class to which each one is mapped.
If you use this older technique, note the following points:
Inheritance of Custom Headers
If you create a subclass of this web service, that subclass inherits the SOAPHEADERS parameter. This is true even if SOAPMETHODINHERITANCE is 0.
Using Header Elements
To use specific SOAP header elements after receiving a request message, use the HeadersIn property of the service or client.
For each supported header element, the service or client creates an instance of the appropriate header class and adds the header to the inbound header array, which is the HeadersIn property. This property is an array with the usual array interface (for example, SetAt(), Count(), and GetAt() methods). The web service or web client can then act on these headers as appropriate.
Note:
The header element namespace is not used for matching the header element in the list. However, the header element namespace in the SOAP message must be the same as specified by the NAMESPACE parameter in your header element subclass; otherwise, an error occurs when the message is imported.