Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
Arundathi
Participant
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.
1 Comment
Labels in this area