Technical Articles
Available Types for the Message Body in CPI Groovy Script
Using Groovy script is the best way to manipulate the message body for complex mapping requirements. As you have noticed you can choose to get different Java types out of the message body. I did some research to find out what lies underneath and what the available options are.
getBody(Which.class)
Let’s get an error first:
//?
def root = new XmlSlurper().parseText(message.getBody())
Error:
com.sap.it.rt.adapter.http.api.exception.HttpResponseException: An internal server error occured: No signature of method: groovy.util.XmlSlurper.parseText() is applicable for argument types: (org.apache.camel.converter.stream.InputStreamCache) values: [org.apache.camel.converter.stream.InputStreamCache@6a461c05]
Possible solutions: parseText(java.lang.String), parse(java.io.File), parse(java.io.InputStream), parse(java.io.Reader), parse(java.lang.String), parse(org.xml.sax.InputSource).
This error lists a lot of options. But did you know that you can also get a Document object?
def root = message.getBody(org.w3c.dom.Document)
For comparison, SAP Help Documentation only lists these types for getBody method:
- String
- InputStream
- byte[]
The conversion feature comes from Apache Camel’s type converters: https://camel.apache.org/manual/latest/type-converter.html
Unfortunately, there is no exhaustive list, and type converters are very dynamic. It is very common to use even custom classes to pass data in Apache Camel.
setBody(Object)
You may also use setBody method to reduce your code at the end of your script:
//org.w3c.dom.Document
message.setBody(myDocument);
You can experiment with the types, but you should check the result! setBody method even accepts groovy.util.Node but it doesn’t convert it to XML!
Script:
def root = new XmlParser().parse(body)
root.A[0].value = "Groovy was here."
message.setBody(root)
Result:
root[attributes={}; value=[A[attributes={}; value=Groovy was here.]]]
Performance
As mentioned in the docs, you will pay a performance fine based on the message body size if you convert from InputStream to String and then parse it to an XML object again. Another thing the above error tells that the message is stored in memory as an InputStream. So using InputStream and its wrappers whenever possible is the safe bet.
Unnecessary resource usage per message:
def body = message.getBody(java.lang.String)
def root = new XmlParser().parseText(body)
Better:
def body = message.getBody()
def root = new XmlParser().parse(body)
Conclusion
It is very nice not to think about some verbose conversion code at the start. You may have more options than you think!
Another idea: In SAP PI/PO we had both the InputStream and OutputStream given by reference at our fingertips. In CPI, the Groovy function has to return before further processing starts. So the system can’t optimize for the bytes already written and writing to an OutputStream does not bring additional value.
I wonder if CPI will allow some streaming/reactive integrations in the future. What are the possibilities if we could read a big file(which allows for partial processing) part by part from an SFTP/HTTP request, process, and write it simultaneously to somewhere else?
Nice blog, thanks for sharing!
BR,
Rashmi
Thanks for the feedback Rashmi!
Best regards,
Fatih
Great Blog.Thanks for sharing!
Thank you,
Syam
Thanks for the feedback Syam!
Regards,
Fatih
Hello Fatih
Amazing post. Thanks for sharing.
However i was wondering, is there a way to generate a .ics(calendar) file using CPI groovy scripts.?
Reards
Aniket
Hello Aniket, thanks for the feedback!
I believe It is totally possible to generate a ".ics" iCalendar file. I think the best way is to use a Java library like this:
https://github.com/ical4j/ical4j
You should import the Jar as a resource and use the library from Groovy script. Or you can do the whole mapping in Java and call the transformation in the Groovy script. I have documented the second option here:
https://blogs.sap.com/2018/03/19/using-java-mappings-in-sap-cloud-platform-integration-cpi/
It is a text format but if you don't use a library you may need to refer the specification: https://tools.ietf.org/html/rfc5545
Regards,
Fatih
Thank you so much for your help!
Regards
Aniket