Modularising CPI Groovy scripts using POGO
Introduction
As with any programming language, the aim is to always modularise the code so that it can be “written once, and used in many places”.
This is no different in CPI where one of the two scripting languages available is Groovy. While it is very easy to create Groovy scripts in CPI, when the integration flow becomes more complex, inevitably there may be occasions where the same logic is repeated in different scripts. This presents an opportunity to modularise and simplify the development.
One approach to perform such modularisation is by using Plain Old Groovy Objects (POGO), which are the Groovy equivalent of POJO. In short, they are just Groovy classes as opposed to the Groovy scripts that are typically generated by the CPI development tools.
Where is my package?
If you are one of those who have already fully jumped onto the WebUI bandwagon, it might not be that obvious how this can be performed or achieved. This is because every class needs to belong to a package, but when you develop in WebUI, the structure of the project is not visible.
Have no fear, Eclipse to the rescue!
Just create a dummy integration project in Eclipse, and you can see the project structure. Groovy scripts typically are automatically created in the src.main.resources.script folder, so this would be a good choice for our POGO’s package.
Sample POGO
Following is a sample of a simple Groovy class (named MessageHelper) containing the following commonly used logic in CPI:-
- Retrieving content from a message header
- Logging content into the Message Processing Log’s attachment
package src.main.resources.script
import com.sap.gateway.ip.core.customdev.util.Message
import com.sap.it.api.msglog.MessageLogFactory
class MessageHelper {
Message msg
MessageLogFactory logFactory
String getHeaderValue(String headerName, String defaultValue) {
def headerValue = this.msg.getHeaders()[headerName]
if(headerValue)
headerValue
else if(defaultValue)
defaultValue
else
throw new RuntimeException("Header $headerName do not exist")
}
String getHeaderValue(String headerName) {
getHeaderValue(headerName, null)
}
void logToMPL(String logName, String content) {
def messageLog = this.logFactory.getMessageLog(this.msg)
if (messageLog) {
messageLog.addAttachmentAsString(logName, content, "text/plain")
}
}
}
With the Groovy code in place, you just need to place them into the Integration Project. With Eclipse, it is just as easy as creating a Groovy class in the right package folder.
However, if you are working in WebUI, the following current limitations necessitate a slightly different approach:-
- Groovy source codes can only be created via a new Groovy Script step (cannot be independently created in the project)
- Groovy scripts are automatically named scriptN.groovy, and cannot be renamed.
As such, it is better to create the source code (either the full logic or just a skeleton) with the appropriate class name, and upload it using the Resources Management functionality of the WebUI.
Using our new POGO
To use our new POGO, we can simply have an integration flow with a Groovy script as shown below.
Following is the sample logic of the script. Take note that it is important to declare the import statement for the above created class.
Note how the modularisation has significantly simplified the logic required to retrieve a header value and log it into the MPL.
import com.sap.gateway.ip.core.customdev.util.Message
import src.main.resources.script.MessageHelper
def Message processData(Message message) {
MessageHelper helper = new MessageHelper(msg: message, logFactory: messageLogFactory)
def httpMethod = helper.getHeaderValue('CamelHttpMethod')
helper.logToMPL('Header Details', "Value of CamelHttpMethod is $httpMethod")
return message
}
And when we run a sample test, voila, it produces the expected results.
Conclusion
While Groovy provides a delightful scripting environment to implement custom logic in CPI, do be cautious in creating too many scripts that have significant portions that are copied from another script.
Be diligent in simplifying and modularising to achieve a lean and clean development.
Nice blog Eng Swee:)
This way integration developers can reduce the complexity of the groovy scripts by placing the common logics under one package.
A blog worth bookmarking.
I've copied and pasted way too many Groovy scripts and will find this much neater and more efficient.
Thank you for sharing.
Nice one! I love easy to read instructions.
Michelle
Hi Eng Swee,
Good one, Nice blog with clear instructions.
Praveen
Hi Eng Swee,
Good one, this way we can have some structure in the groovy mess 🙂
Thanks,
Harsh
Hello Eng Swee,
Thanks for the Blog. I have the following question:
Does the "Upload Resource" take place in each Integration flow in which we need to use the script ?
If we have to make a change to the script, do we have to upload it again to all the Integration flows ?
Nice blog
Found this article today and I am unable to get the "import src.main.resources.script.xxx" to work correctly. I have uploaded my groovy script with the class name etc. Any help?
Hi,
I am having an issue importing the classes if in case there are multiple classes present in my single groovy script file. But the Groovy Language as such supports it
Is it a limitation in the SAP CPI
Kindly let me know
How to use a Groovy class that is referenced in Resources->References?