Skip to Content
Technical Articles
Author's profile photo Arundathi Sarala

Send cXML Message with multiple attachments to Ariba Network as MIME Multipart

Requirement:
Recently I had a requirement to send cXML message with multiple attachments to Ariba network as MIME multipart. Below is the detailed requirement.

Overview:
The source is a zip file with xml and attachments (pdf, word, excel, txt). I had to create a cXML file from xml and send cXML message (attachments filenames need to be part of “Comments” segment in cXML) with encoded attachments to Ariba network as MIME multipart. The challenge here was the attachments count is not same in each source zip file. This was not achievable using standard MIME Multipart encoder.

Solution:

As the attachments count is not fixed, a recursive local process is designed to create MIME multipart for each file and in the end, all are gathered and sent to Ariba Network. To achieve this, I have used 3 processes:

  1. Integration Process: Main integration process-P1
  2. Local integration process : Store Files – P2
  3. Local integration process: Mapping & MIME – P3

 

Integration Artifact Details: Process: Main integration process – P1

Step1: Groovy script: Declare the HashMap and array attribute Filename1

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
def Message processData(Message message) {
//Declare HashMap , array attribute Filename1 and attachments properties

HashMap PayloadHashMap = new HashMap<String,String>();

def Filename1 = []
def Attachment =""
def SourceFilename = message.getHeaders().get("CamelFileName")

message.setProperty("PayloadHashMap", PayloadHashMap)
message.setProperty("Filename1", Filename1)
message.setHeader("SAP_ApplicationID",SourceFilename)
message.setProperty("Attachment",Attachment)
return message; 

}

Step2: Zip splitter: Extracts each file

Step3: Base64 Encoder: Encodes unzipped file

Step 4: Process Call To store Files

Step 5:  Gather all the MIME files

Step 6: Content modifier: Add Content Type to Ariba Multipart

Source value: multipart/related; boundary=”110446448544001″;type=”text/xml”;start=”<4c07a241-26c8-11e5-95bb-e06995c17823_031@test.com>”

Boundary value is a separator for cXML and encoded attachments. I have used a random number.

Step 7: Content Modifier: Adding Attachments

Step 8: HTTPs Call: Ariba_HTTP_Request Reply
Ariba Shared secrete credentials are sent as part of cXML

Step 9: Content Modifier: Capture Ariba response

Integration Artifact Details: Process: Store Files – P2

Step 1: Groovy Script: Storing Files in HashMap

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
def Message processData(Message message) {
    String body = message.getBody(java.lang.String) as String

    def map = message.getProperties();
    def Filename1 = message.getProperties().get("Filename1")
    def PayloadHashMap = map.get("PayloadHashMap");
    def filename = message.getHeaders().get("CamelFileName")

   //Store filename and body in HashMap, Filename in array attribute Filename1
    PayloadHashMap.put(filename,body)
    Filename1.push(filename)


    message.setProperty("PayloadHashMap", PayloadHashMap)
    message.setProperty("Filename1", Filename1)

return message; 

}

Step 2: Loop process call: Mapping & MIME Process Call
Max number of Iterations =10 ( max number of attachments expected in zip file)

 

Integration Artifact Details: Process: Mapping & MIME – P3

Step 1: Groovy script: Fetch the body of 1st entry in HashMap table

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
def Message processData(Message message) {
    
    def map = message.getProperties();
    def PayloadHashMap = map.get("PayloadHashMap");
    //Fetch body of the 1st entry of HashMap
    def Filename = message.getProperties().get("Filename1")[0]
    def PayloadNew = "";
    PayloadNew = PayloadHashMap.get(Filename); 

     message.setBody(PayloadNew);


message.setProperty("PayloadNew", PayloadNew);

return message;

}

Step 2: Content Modifier: Capture the message ID and current timestamp required in cXML
Message ID and current timestamp values are used in mapping.

Step 3: Router: checks if file is empty

${property.PayloadNew} = null or ${property.PayloadNew.trim().length()} = ‘0’ or ${property.PayloadNew.trim()} = ‘””‘

Step 4: Groovy script: Capture Data: Delete 1st entry of HashMap and array attribute Filename1; Capture file attachment details

import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import groovy.xml.MarkupBuilder
def Message processData(Message message) {
    
    def map = message.getProperties();
    def PayloadHashMap = map.get("PayloadHashMap");
    def Filename = message.getProperties().get("Filename1")[0]
    def PayloadNew = PayloadHashMap.get(Filename); 

    // Delete 1st entry of Hashmap and array attribute Filename1;

    def packages = message.getProperties().get("Filename1").reverse() as Stack
    packages.pop()
    packages = packages.reverse() as Stack
    message.setProperty("Filename1", packages)
    PayloadHashMap.remove(Filename);

// Capture file attachment details
 def Attachment = message.getProperties().get("Attachment")
        def writer = new StringWriter();
    def builder = new MarkupBuilder(writer);
    def urlFilename = Filename.substring(Filename.indexOf('/')+1);
    urlFilename = 'cid:'+urlFilename + '@test.com'
    def FileType = Filename.substring(Filename.indexOf('.')+1);

        if (FileType != 'xml')
        {
            builder.Attachment
             {
                if (FileType != 'xml')
                'URL'(urlFilename)
            
             }
        }
    Attachment = Attachment + writer.toString(); 
message.setProperty("Attachment", Attachment);
message.setProperty("PayloadNew", PayloadNew);
message.setProperty("PayloadHashMap", PayloadHashMap);

return message;

}

Step 5: Router: Checks if file is xml

Step 6: Base64 Decoder

Step 7: Content Modifier: Ariba Header Parameters
Pass the Ariba header parameters required in cXML to connect to Ariba Network

Step 8: Message mapping: Map_xml_to_cXML
Message mapping to convert xml to cXML

Step 9: Content Modifier: Capture Header Comments

Store the “Comments” segment details from cXML, these details will be replaced by attachments details later in main process.

Step 10: XSLT Code: Handling xml:lang in cXML

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output indent="yes" method="xml"/>
    <xsl:template match="/">
	<xsl:text disable-output-escaping="yes">
&lt;!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.055/InvoiceDetail.dtd"&gt;
</xsl:text>
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
     <!--Replaces “lang” with “xml:lang” in cXML-->
    <xsl:template match="@lang">
        <xsl:attribute name="xml:lang">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

Replaces “lang” with “xml:lang” in cXML

Step 11: Content Modifier: Added ContentType and ContentID

Step 12: Content Modifier: Capture cXML Payload

Step 13: Groovy script: Capture Data : Common script for Step 4 and step 13

Step 14: Groovy script: Check File Type Extension

“ContentType” fetched from value mapping table.

import com.sap.gateway.ip.core.customdev.util.Message
import java.util.HashMap
import com.sap.it.api.ITApiFactory
import com.sap.it.api.mapping.ValueMappingApi


def Message processData(Message message) {
                                //Rerieve Input Data
                                def body = message.getBody(java.lang.String) as String;

                                //Declare value mapping table
                                def valuemap = ITApiFactory.getApi(ValueMappingApi.class, null);
                                def SAgency = "InvoiceSystem";
                                def SIdentifier = "FileExtension";
                                def TAgency = "Ariba";
                                def TIdentifier = "ContentType";
                                def CamelFileName = message.getHeaders().get("CamelFileName")
                                def Key = CamelFileName.substring(CamelFileName.indexOf(".")+1 , CamelFileName.length());
                                def filename = CamelFileName.substring(CamelFileName.indexOf("/")+1 , CamelFileName.length()); 

                                 //Fetch value mapping table details
                                def ContentType = valuemap.getMappedValue(SAgency,SIdentifier,Key,TAgency,TIdentifier);
                                message.setProperty("ContentType", ContentType)
                                message.setProperty("filename", filename)
                
                return message;
}

Value mapping table:

Step 15: Content Modifier : Capture ContentType And FileName

Testing:
Zip file placed in source SFTP:

 

cXML MIME request sent to Ariba:

MIME with 5 attachments sent to Ariba:

Ariba response in CPI:

Conclusion:
We saw how to send cXML message with multiple attachments to Ariba Network.
If the xml is missing in the zip file, message status will be successful in CPI with HTTP 500 error response from Ariba. If zip file has only xml, then cXML will be sent to Ariba. Messages status will be successful in CPI with HTTP 200 response from Ariba.

Assigned Tags

      1 Comment
      You must be Logged on to comment or reply to a post.
      Author's profile photo Gopinatha Ashwathareddy
      Gopinatha Ashwathareddy

      hi Arundathi Sarala

       

      Please let me how to add the in cxm

      !DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.056/InvoiceDetail.dtd