A few days ago I answered
this interesting question by Florian Kube in the Questions & Answers area. It struck me that the solution might be of more general interest, so in this blog post I’m going to expand a bit on my answer.
Florian’s scenario is this: He picks up an email with a sender Mail channel. The email has an XML attachment, and it is the contents of this attachment, he wants to process. He therefore needs to replace the message body with the attached XML document, and then proceed with mapping and so forth.
I’m going to show you how to solve this problem using scripting. The code is written in Groovy, but if your prefer JavaScript, translating it is straightforward.
Methods of the Message class
Access to the body and attachments of a message is provided by the
com.sap.gateway.ip.core.customdev.util.Message
object, which the runtime passes to your Groovy function. The API documentation available for this interface is available
here.
The two methods, we are going to use, are
getAttachments
and
setBody
. The former returns a
java.util.Map
object containing the message’s attachments, and the latter sets a new message body.
Extracting the attachment contents
Let us deal with the attachment first, since that is the more complicated part. The keys of the
Map
returned by
getAttachments
are attachment names, and the values are
javax.activation.DataHandler
objects. The
DataHandler
objects contain the actual attachment data. Given the scenario, we assume that the
Map
contains exactly one attachment, but we do not know its key ahead of time.
In order to get the
Map
’s only value without knowing its associated key, I retrieve the
Collection
of all the
Map
’s values and iterate it once. The code looks like this (required
import
statements not shown):
Map<String, DataHandler> attachments = message.getAttachments()
Iterator<DataHandler> it = attachments.values().iterator()
DataHandler attachment = it.next()
(You
could combine the three lines into a single line, if you are so inclined, but that would make the intention of the code less clear, IMHO.)
Setting the message body
The
DataHandler
class offers a couple of different ways to get at the wrapped data. We are going to use the
getContent
method, which returns a
java.lang.Object
object. Why? Because an
Object
instance is what the
setBody
method of the
Message
class expects. Here is the code that replaces the message body:
message.setBody(attachment.getContent())
Putting the pieces together
We are now ready to put it all together. Here is the complete script:
import com.sap.gateway.ip.core.customdev.util.Message
import java.util.Map
import java.util.Iterator
import javax.activation.DataHandler
def Message processData(Message message) {
Map<String, DataHandler> attachments = message.getAttachments()
Iterator<DataHandler> it = attachments.values().iterator()
DataHandler attachment = it.next()
message.setBody(attachment.getContent())
return message
}
In order to use it, put the code in a Script step at the very beginning of your integration flow. After this step, proceed with whatever processing your scenario requires.
How to handle messages with no attachments
Keep in mind that the script assumes that the message has exactly one attachment. If it does not have any attachments, the code will fail. Determining
why it fails, is left as an exercise for the reader
🙂
If this assumption is not always met in your particular scenario, you can test for the presence of attachments, by checking whether the
Map
returned by
getAttachments
is empty. You do this by calling its
isEmpty
method as follows:
import com.sap.gateway.ip.core.customdev.util.Message
import java.util.Map
import java.util.Iterator
import javax.activation.DataHandler
def Message processData(Message message) {
Map<String, DataHandler> attachments = message.getAttachments()
if (attachments.isEmpty()) {
// Handling of missing attachment goes here
} else {
Iterator<DataHandler> it = attachments.values().iterator()
DataHandler attachment = it.next()
message.setBody(attachment.getContent())
}
return message
}