Skip to Content
Technical Articles
Author's profile photo Yayati Ekbote

Send cXML Message to Ariba Network as MIME Multipart

Hello friends,

I am a bit new to SAP Cloud Integration and I started learning and working on SAP Cloud Integration to integrate Ariba Sourcing via Ariba Network Quote Automation with non SAP ERP.

Initially, I tried to do a lot of research on Ariba adapter provided by SAP but I gave up when I came to know about its limitations. Ariba adapter on SAP CPI is no match to its old counter part of SAP PI. Probably it will be in future, but for now it is not much of a use.

Anyway, my target was to send Quote Request (Sourcing Request) to Ariba Network as MIME Multipart message. I started googling and looking into SAP standard I-Flows, expert blogs and discussions. Out of all,I gave a try to one of the blog where the cXML and attachment were fetched as SFTP files and then fed to MIME Mulitpart encoder. I tried to build the I-Flow in same manner but Ariba Network kept responding error regarding MIME message format. Errors like –

No content allowed before prolog or HTTP 500 error server side error.

Also, as I am getting attachments as base64 encoded string already part of JSON, decoding to attach as attachment object to message and then MIME Multipart encoder encoding again was unnecessary.

Finally, I decided to build the payload using a custom approach just the way Ariba Network wants and send it over standard HTTP receiver adapter.

From customer’s source system, I am getting the RFQ as a JSON payload with attachments as base64 encoded string inside the body.

A test payload from Postman looks like this –

Attachments section is Array in the Quote Request Header section

Here is how my I-Flow looks like this –

I-Flow%20Main%20Process

I-Flow Main Process

  1. First Step was to convert the incoming JSON file to XML format using XML to JSON converter.
  2. Next, I used Content Modifier to have configurable exchange properties. Like Buyer AN ID, Ariba AN ID, System ID, Endpoint ID. This information is needed in cXML header section of payload and it is constant information for the customer. Hence I made these as externalized parameters in this content modifier so as to configure production specific values in production tenant.
  3. The Incoming document, may have or may not have attachments. So using router, I am checking if the attachments section is present in the incoming payload. If not, then default route route1 handles only the main cXML body. If present, then route2 handles payload with attachments. Router%20Route%202
  4. Next, via Sequential Multicast, first I am preparing cXML body with the data of quote request document. For this, I added a separate local integration sub flow.
    1. Generate a unique payload ID and get shared secret of endpoint using groovy script –
      import com.sap.gateway.ip.core.customdev.util.Message;
      import java.util.HashMap;
      import com.sap.it.api.ITApiFactory;
      import com.sap.it.api.securestore.*;
      import com.sap.it.api.keystore.*;
      
      def Message processData(Message message) {
          
          def map = message.getProperties();
          def credAlias = map.get("EndPointCreds");
          def service = ITApiFactory.getService(SecureStoreService.class, null);
          def creds = service.getUserCredential(credAlias);
          def ss = creds.getPassword();
             
          message.setProperty("SharedSecret", ss);
          
          def payloadId = UUID.randomUUID().toString();
          message.setProperty("PayloadID", payloadId);
          return message;
          
      }
    2.  I used XSLT mapping to map the incoming fields and externalized parameter values to map to outgoing cXML. Follow the cXML reference guide for exact fields. Only tip here pertaining to this i-flow is, the content ID of the attachment part is needed as in the /QuoteRequestHeader/Comments section. This way the attachment part is connected to main cXML part.
      <Attachment>
      	<URL>cid:XXXXX00000000000XXXXXX00000000XXXX</URL>
      </Attachment>
      <Attachment>
      	<URL>cid:YYYYY00000000000YYYYYY00000000YYYY</URL>
      </Attachment>​
    3. Then I added the Multipart boundary to the generated cXML
  5. Once the main sub process is over, I am adding a newline character. This is done so that when join and gather combine the cXML and attachment parts using concatenate, it adds it at new line. If the Quote Request message does not have any attachments, then new line character is not added.
    Very simple groovy script to add new line char.

    import com.sap.gateway.ip.core.customdev.util.Message;
    import java.util.HashMap;
    def Message processData(Message message) {
        //Body 
           def body = message.getBody(java.lang.String);
           message.setBody(body + "\n");
           return message;
    }​
  6. In the 2nd branch of sequential multicast, I am extracting attachment section and add it as part of the Multipart message.
    1. In first sub step, I am using Iterating splitter to handle each attachment(in case of multiple) separately.
      Expression Type : XPATH
      XPath Expression : /QuoteRequest/QuoteRequestHeader/Attachments
    2. In Content Modifier, add the file attributes and Multipart boundary. In exchange properties, using XPath, I am extracting the file attributes like File Name, Content-Length, File Type etc..
      Name Source Type Source Value Data Type Default Value
      fileContent

      XPath

      /Attachments/Content java.lang.String
      /Attachments/contentType java.lang.String
      fileName

      XPath

      /Attachments/fileName java.lang.String
      /Attachments/contentLength java.lang.String
      fileContentID

      XPath

      /Attachments/contentID java.lang.String

    3. Add new line character using groovy script. Only variation here I am using is, if it is a last attachment part, then new line character is not needed. So, I am checking SAP standard property CamelSplitComplete. If it is not last split, then keep on adding new line character. If it is the last split, then do not add new line character. If newline character gets added after end of entire message, Ariba Network throws error like EOF skipping headers

      import com.sap.gateway.ip.core.customdev.util.Message;
      import java.util.HashMap;
      def Message processData(Message message) {
          //Body 
          def map = message.getProperties();
          def last = map.get("CamelSplitComplete");
          def tom = 0;
          if( last == false){
              tom = 1;
              message.setProperty("done",tom );
              
              def body = message.getBody(java.lang.String);
              message.setBody(body + "\n");
      
          } else {
              message.setProperty("done",tom );
      
          }
          
          return message;
      }​
    4. Gather all the attachment parts using Concatenate aggregation algorithm. Incoming format I kept as Plain Text.
  7. Join the Sequential multicast branches and gather to concatenate.
  8. In the step 9 Content Modifier, I added the header parameter
    Source Type Source Value
    Constant Multipart/mixed; boundary=”kdflkajfdksadjfk”;type=”text/xml”
  9. Step 10 was important to convert entire payload as String type other wise the HTTP adapter with HTTP POST call has limitation that makes Ariba Network respond with HTTP 411 Length. required exception.
    The link of guided answers from SAP about HTTP receiver adapter asks to convert the payload as byte array/string https://ga.support.sap.com/dtp/viewer/index.html#/tree/2237/actions/28748:45399:41513:41515:44262

    import com.sap.gateway.ip.core.customdev.util.Message;
    import java.util.HashMap;
    def Message processData(Message message) {
        //Body 
           def body = message.getBody(java.lang.String);
           long msgSize = body.getBytes().length;
           String payloadSize = msgSize.toString();
           message.setBody(body);
           message.setHeader("Content-Length",payloadSize);
    
           return message;
    }​

     

  10. Lastly, I used HTTP adapter with Request Reply step to send the final payload to Ariba Network

The response from Ariba Network in CPI trace

Once Ariba Network successfully accepts the cXML mulitpart message, it responds with HTTP 200. This I am storing it to log custom header properties for monitoring purpose. AN’s responds with XML message which I am converting to JSON so that the source system receives the success/failure in the format which they accept.

Also, I have added some exception handling. If there is any exception in message processing, we are triggering email to administrator.

 

Let me know your views and comments.

 

Regards,

Yayati Ekbote

Assigned Tags

      6 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Scar Ai
      Scar Ai

      Wow, It's awesome sharing, I really suffered by the 411 for several days, Thanks for it 🙂

      Author's profile photo Madhavi Mattegunta
      Madhavi Mattegunta

      Hi,

      I have a scenario of integrating with CPI from Ariba NW to SAP S/4 for InvoiceDetail and by using Ariba adapter, CXML is only coming in the body of the message and attachments are separate. I am facing challenge in co-relating the CXML with attachment, more specifically is it file name or content id which should be used, and how to extract content id from attachment?

      Author's profile photo Yayati Ekbote
      Yayati Ekbote
      Blog Post Author

      Hello Madhavi,

       

      Sorry I noticed your comment very late. The relation to attachment is via content ID.

      If you are receiving Invoice cXML with attachments from Ariba, then it is mostly MIME Multipart message. You will have use Multipart decoder in CPI. This will extract attachment part from MIME message and set it as attachment to your CPI message which you can read via groovy script.

      Regards,

      Yayati

      Author's profile photo Sankara Rao Bhatta
      Sankara Rao Bhatta

      Hi Ekbote,

      Thanks for taking time and writing this wonderful blog. I am trying a similar thing for sending PO to AN with attachments. I am trying currently with postman tool. I have pasted content in the postman request body. is the content needs to be in a single line ( or) it has to be in an xml format. when you mentioned you have added header parameter multipart/ mixed and boundary values, are they part of the payload ( or) they go as HTTP headers? can you paste the actual payload before it goes to Ariba?

       

      Author's profile photo Yayati Ekbote
      Yayati Ekbote
      Blog Post Author

      Hello Sankara,

      Refer to cXML reference guide or cXML solutions guide where you will get exact specifications of how AN requires the payload to be. AN reads cXML (Content-Type = application/xml) or cXML with attachments are MIME Multipart message.

      Hope this clarifies.

       

      Regards,

      Yayati

      Author's profile photo Sankara Rao Bhatta
      Sankara Rao Bhatta

      HI,

       

      I have solved it, bascaily the content in each boundary needs to be in a single line and there has to be one empty row between bounday value and actual content