Search code examples
springsoapspring-integrationspring-ws

Set spring integration header into soap header in spring integration (without interceptor/ threadlocal)


Is there anyway to set SOAP-ENV header in spring integration xml from spring integration headers ?

I tried below approach and expected bId to be populated to soap headers

<int:chain id="soapcall" input-channel="soapchannel">      
        <int-xml:header-enricher>
            <int-xml:header name="bId" expression="headers['bId']"/>
        </int-xml:header-enricher>
          <int-ws:outbound-gateway  uri="${soap.url}" interceptor="myInterceptor">
          </int-ws:outbound-gateway> 
     </int:chain>

However Actual output doesn't have the header. see below:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
                   xmlns:n1="http://namespace/n1">
   <SOAP-ENV:Header/>
   <SOAP-ENV:Body> ...
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

I also looked into below approach inside chain before calling outbound gateway. It seems this header enricher takes only soap action as header. So this throws exception action headers not found

<int-ws:header-enricher >
            <int-ws:soap-action expression="headers['bId']"/>
          </int-ws:header-enricher>

I also looked into this post. But I couldn't get this compiled inside a chain.


Solution

  • I'm not sure what is the <int-xml:header-enricher>, but it doesn't matter.

    What you need is called header-mapper on the <int-ws:outbound-gateway>.

    Its code looks like:

    @Override
    protected void populateStandardHeaders(Map<String, Object> headers, SoapMessage target) {
        String soapAction = getHeaderIfAvailable(headers, WebServiceHeaders.SOAP_ACTION, String.class);
        if (!StringUtils.hasText(soapAction)) {
            soapAction = "\"\"";
        }
        target.setSoapAction(soapAction);
    }
    
    @Override
    protected void populateUserDefinedHeader(String headerName, Object headerValue, SoapMessage target) {
        SoapHeader soapHeader = target.getSoapHeader();
        if (headerValue instanceof String) {
            QName qname = QNameUtils.parseQNameString(headerName);
            soapHeader.addAttribute(qname, (String) headerValue);
        }
    }
    

    So, by default it maps WebServiceHeaders.SOAP_ACTION as a standard one, and all those user defined if they are String and only as attribute of the target SOAP-ENV:Header element.

    Those user defined headers can be mapped by the:

    <xsd:attribute name="mapped-request-headers" type="xsd:string">
                <xsd:annotation>
                    <xsd:documentation><![CDATA[
    Comma-separated list of names of SOAP Headers to be mapped from the SOAP request into the MessageHeaders.
    This can only be provided if the 'header-mapper' reference is not being set directly. The values in
    this list can also be simple patterns to be matched against the header names (e.g. "foo*" or "*foo").
                            ]]></xsd:documentation>
                </xsd:annotation>
            </xsd:attribute>
    

    If you need to populate sub-elements to the <SOAP-ENV:Header>, you don't have choice unless extend DefaultSoapHeaderMapper and override that populateUserDefinedHeader() and use SoapHeader.addHeaderElement() API.

    Also look into the Reference Manual.