Technical Articles
Create MIME Multipart SOAP message in SAP CPI to be delivered to S4 HANA Cloud system accepting MTOM MIME messages
Background
During an implementation of integration between Ariba Cloud Integration gateway (Using SAP CPI)and S4 HANA Cloud system, we identified that even though the SOAP adapter in SAP CPI does support MIME messages and is SOAP 1.2 compliant, it doesn’t support MTOM messages. S/4 HANA Cloud system supports MTOM MIME messages received via SOAP adapter and was expecting the SOAP MIME message in MTOM format this integration scenario.
Upon recommendation , we were able to achieve the integration by building a MIME SOAP envelope in compliance with MTOM and delivery via HTTP adapter to S4 HANA Cloud system.
Implementation
I have used groovy script to build custom MIME envelope in compliance with MTOM.
MTOM requirements
For MTOM SOAP content-type should be as below
- Content-Type: application/xop+xml; charset=utf-8; type=”text/xml”
Integration Flow
Pre-Requisites
S/4 HANA Cloud requires the following additional headers in the MIME
Content-Length of each MIME part
Content-Length of complete MIME Envelope
Here is the iflow implementation of the MIME envelope
- Receive MIME Envelope – via HTTP Sender Adapter
- Parse the MIME using MIME Multipart Decoder Component provided by CPI
- Script to get the size of actual payload
- Script to build the MIME envelope in compliant with MTOM
- Script to get the size of Complete MIME SOAP Envelope
- Deliver it to target via HTTP Receiver Adapter using Request/Reply component and capture the Response received .
Script to get payload size and to get size of the complete MIME Envelope
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
def Message processData(Message message) {
//Body
long payloadSize = message.getBodySize();
String PayloadSize = payloadSize.toString();
message.setHeader("PayloadSize", PayloadSize);
return message;
}
Script to build MIME Envelope
import com.sap.gateway.ip.core.customdev.util.AttachmentWrapper;
import com.sap.gateway.ip.core.customdev.util.Message;
import org.apache.camel.impl.DefaultAttachment;
import javax.mail.util.ByteArrayDataSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.camel.Attachment;
import javax.activation.DataHandler;
import java.util.Iterator;
import org.apache.commons.io.IOUtils;
import java.lang.Byte;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import java.lang.StringBuilder;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
def Message processData(Message message) {
//Body
byte[] payload = message.getBody(byte[].class);
String attType
String attName
String attSize
String attContentId
String source = null
def map = message.getHeaders();
String SOAPEnvelopeSize = map.get("PayloadSize")
// Data source
MimeMessage mimeMessage = new MimeMessage(source);
def MimeMultipart mimeMultipart = new MimeMultipart("related");
//SOAP Payload
def MimeBodyPart soapapayload = new MimeBodyPart();
soapapayload.setHeader("Content-Length", SOAPEnvelopeSize)
ByteArrayDataSource soapDataSource = new ByteArrayDataSource(payload, "application/xop+xml")
soapapayload.setDataHandler(new DataHandler(soapDataSource));
soapapayload.setHeader("Content-Type", "application/xop+xml; charset=utf-8; type=\"text/xml\"")
mimeMultipart.addBodyPart(soapapayload)
//get and set attachments
def attMap = message.getAttachments();
def AttCount = attMap.size()
if(AttCount > 0)
{
Map<String, AttachmentWrapper> attMapN = message.getAttachmentWrapperObjects();
Iterator<Entry<String, AttachmentWrapper>> attIteratorN = attMapN.entrySet().iterator();
int j = 1;
while(attIteratorN.hasNext())
{
Entry<String, AttachmentWrapper> entryN = attIteratorN.next();
AttachmentWrapper attachment = entryN.getValue();
DataHandler dataHandler = attachment.getDataHandler();
InputStream inputStream = dataHandler.getInputStream();
byte[] bytes = IOUtils.toByteArray(inputStream);
int EachAttachmentSize = bytes.length
attSize = Long.toString(EachAttachmentSize)
def MimeBodyPart soapAttachmentBodyPart = new MimeBodyPart();
Collection<String> headerList = attachment.getHeaderNames();
soapAttachmentBodyPart.setDataHandler(dataHandler)
for (String attachmentHeaderName : headerList) {
String attachmentHeaderValue = attachment.getHeader(attachmentHeaderName);
soapAttachmentBodyPart.addHeader(attachmentHeaderName, attachmentHeaderValue);
}
mimeMultipart.addBodyPart(soapAttachmentBodyPart)
j++;
}
}
StringBuilder builder
String searchStr
String replaceStr
String resultString
String mimeContentType = mimeMultipart.getContentType();
builder = new StringBuilder(mimeContentType);
searchStr = "multipart/related"
replaceStr = "Multipart/Related;type=\"application/xop+xml\"; start-info=\"text/xml\""
resultString = stringReplaceAll(builder, searchStr, replaceStr)
message.setHeader("Content-Type",resultString);
ByteArrayOutputStream boas = new ByteArrayOutputStream();
mimeMultipart.writeTo(boas);
message.setBody(boas);
message.setHeader("accept","application/xop+xml ,text/xml")
return message;
}
def stringReplaceAll(builder, String from, String to)
{
int index = builder.indexOf(from);
while (index != -1)
{
builder.replace(index, index + from.length(), to);
index += to.length();
index = builder.indexOf(from, index);
}
String replacedString = new String(builder);
return replacedString;
}
Conclusion
This is a substitute solution for implementing MTOM MIME message generation in SAP CPI. The MIME Envelope script can be modified as per requirement .
Hi Vinay,
Thanks for your post,
I have one requirement,
i.e
Sender Ariba cxml payload the attachment (“cid:1735239107.1592222922946@cxml.org”)
document is coming in above format need to extract this content and send to base64 with third party… could you please suggest me with your inputs, that how we can extract the content.
It’s very helpful.
Thank you.
Hi Rishab,
You can use the MIME decoder and then use Script API to read the attachments from the exchange and then convert to Base64 and then reassign it back to the exchange .
Vinay