May 12, 2014

Passing SOAP:Header via Split-Join

Most services are having all of their payload’s information in the soap:Body. Some though include meta-information located in the soap:Header.

Surprisingly, Split-Join simply drops the soap:Header values.

The documentation says it should support them, but I failed to make it work.

What to do if you got to pass soap:Header values through Split-Join?

How To Pass SOAP:Header In Plain Split-Join: A Hack

If you have to use the naked Split-Join facility, I pity you. But still, let’s see what can be done.

First obvious thing is we cannot call a backend service directly from the Split-Join. It won’t receive our headers. No matter how we pass the header values, we have to have a normalization proxy between Split-Join and the backend.

Caller -> SaveHeaderProxy -> Split-Join Biz -> Split-Join -> RecoverHeaderProxy -> Biz Service

The easiest hack is to inject the soap:Header as the last element of the message. Yes, the message becomes not schema-valid, but since we do not do a validation in neither Split-Join nor in Normalization proxy, it causes no problems except for some extra CPU cycles.

For example, having the following SOAP Request:

<soapenv:Envelope ...>

  <soap:Header ...>
    <echo:echoStringHeader xmlns:echo="http://gps/echo-with-headers/">
      <echoHeader>header</echoHeader>
    </echo:echoStringHeader>
  </soap:Header>

  <soapenv:Body>
    <echo:echoStringInput xmlns:echo="http://gps/echo-with-headers/">
      <echoInput>string</echoInput>
    </echo:echoStringInput>
  </soapenv:Body>

</soapenv:Envelope>

the SaveHeaderProxy would convert it into

<soapenv:Envelope ...>

  <soapenv:Body>
    <echo:echoStringInput xmlns:echo="http://gps/echo-with-headers/">
      <echoInput>string</echoInput>

      <!-- Saved SOAP:Header; the message is not schema-valid but Split-Join doesn't validate -->
      <echo:echoStringHeader xmlns:echo="http://gps/echo-with-headers/">
        <echoHeader>header</echoHeader>
      </echo:echoStringHeader>

    </echo:echoStringInput>
  </soapenv:Body>
</soapenv:Envelope>

Note that the header must be placed under the first child  of soap:Body, not under soap:Body itself, otherwise Split-Join will complain there is no such part defined in the WSDL. I.e. the following is wrong:

<soapenv:Envelope ...>

  <soapenv:Body>
    <echo:echoStringInput xmlns:echo="http://gps/echo-with-headers/">
      <echoInput>string</echoInput>
    </echo:echoStringInput>

    <!-- Bad! You will get a fault -->
    <echo:echoStringHeader xmlns:echo="http://gps/echo-with-headers/">
      <echoHeader>header</echoHeader>
    </echo:echoStringHeader>

  </soapenv:Body>
</soapenv:Envelope>

restoring-saved-header

Then in the RecoverHeaderProxy proxy get the last element of the message, and, if it is echoStringHeader (in our example), cut it out and insert it back into $header variable.

Hooray, headers has survived Split-Join!

Note: if you need to pass soap:Headers in the response too, you have to do the same trick in the opposite direction. The RecoverHeaderProxy would save the headers as the last element of the payload, and SaveHeaderProxy would extract them and place back under $header variable.

How To Pass SOAP:Header In Plain Split-Join: Purist's Way

tumblr_n0hpv6uow11st5lhmo1_1280

Some people my experience almost a physical pain at the thought of violating the schema. Rules are rules. Alright, let’s review the second option: custom wrapper WSDL.

Let’s make our Split-Join take not the original message type, but a wrapper message containing both the message body and its header.

The overall services lineup looks pretty much the same, but the Split-Join WSDL now accepts the messages of the Wrapper type:

Caller -> WrapperProxy -> Split-Join Biz -> Split-Join -> RestoreProxy [builds original message] -> Biz Service
<Wrapper>
  <Headers>
    ... soap:Headers go here ...
  </Headers>
  <Payload>
    ... request body goes here ...
  </Payload>
</Wrapper>

We are compliant to the schemas now, and achieved the same effect.

How To Pass SOAP:Header In GenericParallel

That all is fine, but both approaches take work. As usual, GenericParallel provides the same functionality with no extra efforts.

In GenericParallel, the Request may contain the request message itself or a soap:Envelope. In the latter case, the Envelope may contain soap:Header section, which will be automatically passed down to the backend service.

      <typ:Request GPSTarget="Profiles/UserProfile">

         <soap-env:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
          <soap-env:Header>
            ... headers here ...
          <soap-env:Header>
          <soap-env:Body>
            <gpsa:GetUserProfileRequest xmlns:gpsa="http://userprofile">
              <gpsa:Data>12345678</gpsa:Data>
            </gpsa:OperationARequest>
          </soap-env:Body>
         </soap-env:Envelope>

      </typ:Request>

That’s all! No other work to do. No need to create your own normalization proxy, either.

Even more: GenericParallel returns whatever soap:Headers are set in the response, if any:

      <types:Response GPSIndex="1" GPSBatchIndex="1">

         <soap-env:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
          <soap-env:Header>
            ... response headers here ...
          <soap-env:Header>
          <soap-env:Body>
           <gpsa:GetUserProfileResponse xmlns:gpsa="http://userprofile">
            <gpsa:UserProfile>...</gpsa:UserProfile>
           </gpsa:GetUserProfileResponse>
          </soap-env:Body>
         </soap-env:Envelope>

      </types:Response>

Still want to use a raw Split-Join? ;)

Vladimir Dyuzhev, author of GenericParallel

About Me

My name is Vladimir Dyuzhev, and I'm the author of GenericParallel, an OSB proxy service for making parallel calls effortlessly and MockMotor, a powerful mock server.

I'm building SOA enterprise systems for clients large and small for almost 20 years. Most of that time I've been working with BEA (later Oracle) Weblogic platform, including OSB and other SOA systems.

Feel free to contact me if you have a SOA project to design and implement. See my profile on LinkedIn.

I live in Toronto, Ontario, Canada.  canada   Email me at info@genericparallel.com