Skip to Content
Technical Articles
Author's profile photo Fatih Pense

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?

Assigned tags

      7 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Rashmi Joshi
      Rashmi Joshi

      Nice blog, thanks for sharing!

       

      BR,

      Rashmi

      Author's profile photo Fatih Pense
      Fatih Pense
      Blog Post Author

      Thanks for the feedback Rashmi!

      Best regards,
      Fatih

      Author's profile photo Syambabu Allu
      Syambabu Allu

      Great Blog.Thanks for sharing!

      Thank you,

      Syam

      Author's profile photo Fatih Pense
      Fatih Pense
      Blog Post Author

      Thanks for the feedback Syam!

      Regards,
      Fatih

      Author's profile photo Aniket Baba
      Aniket Baba

      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

      Author's profile photo Fatih Pense
      Fatih Pense
      Blog Post Author

      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

      Author's profile photo Aniket Baba
      Aniket Baba

      Thank you so much for your help!

       

      Regards

      Aniket