SAP Scripting in CPI (Groovy)
CPI's built-in steps handle the vast majority of integration scenarios without any code. Use graphical mapping, built-in functions, and standard steps whenever possible — they are easier to read, maintain, and debug. Groovy scripting fills the gap when standard steps cannot handle your requirement.
Reach for a Groovy script when you need: complex string manipulation, custom calculation logic, calling a Java library function, manipulating multiple message headers simultaneously, making conditional decisions based on complex business rules, or parsing non-standard data formats that CPI cannot process natively.
Groovy in CPI
CPI supports Groovy as its scripting language. Groovy is a JVM-based language that is very similar to Java but with simpler syntax. If you know Java, you already know most of Groovy. If you do not know Java, Groovy is still approachable — it has simpler syntax than Java, dynamic typing, and many shortcuts that reduce code length.
CPI uses Groovy version 2.4.x. Standard Java libraries and most Groovy libraries are available. External network calls from scripts are restricted for security reasons.
The Script Step in iFlow
Drag a Groovy Script step from the palette onto your iFlow canvas. Double-click it to open the script editor. Every Groovy script in CPI must define a method named processData that accepts a Message object and returns a Message object:
import com.sap.gateway.ip.core.customdev.util.Message
import java.util.HashMap
def Message processData(Message message) {
// Your logic goes here
return message
}
The message parameter gives you access to the message body, headers, and exchange properties. Return the same or modified message object when done.
Reading and Writing the Message Body
def Message processData(Message message) {
// Read the body as a String
def body = message.getBody(String)
// Modify the body
def modifiedBody = body.replace("OLDVALUE", "NEWVALUE")
// Write the modified body back
message.setBody(modifiedBody)
return message
}
For XML bodies, you can use Groovy's built-in XML parser (XmlSlurper) to navigate and modify the structure without writing complex string manipulation:
import groovy.xml.XmlSlurper
import groovy.xml.XmlUtil
def Message processData(Message message) {
def body = message.getBody(String)
// Parse XML
def xml = new XmlSlurper().parseText(body)
// Read a value
def orderID = xml.Header.OrderID.text()
// Modify a value
xml.Header.Status = "PROCESSED"
// Serialize back to String
message.setBody(XmlUtil.serialize(xml))
return message
}
Reading and Writing Headers
def Message processData(Message message) {
// Read a header value
def headers = message.getHeaders()
def contentType = headers.get("Content-Type")
def senderSystem = headers.get("SAP_Sender")
// Write a new header
message.setHeader("X-Processed-By", "CPI-PROD")
message.setHeader("X-Processing-Time", new Date().toString())
// Remove a header
message.getHeaders().remove("Authorization")
return message
}
Reading and Writing Exchange Properties
def Message processData(Message message) {
// Read a property set by an earlier Content Modifier
def props = message.getProperties()
def salesOrderID = props.get("SalesOrderID")
def retryCount = props.get("RetryCount") as Integer
// Increment a counter
retryCount = retryCount + 1
// Write updated value back
message.setProperty("RetryCount", retryCount.toString())
// Write a new property
message.setProperty("ProcessingStatus", "IN_PROGRESS")
return message
}
Throwing Exceptions to Trigger Error Handling
Scripts can deliberately throw exceptions to trigger the iFlow's Exception Sub-Process. Use this for custom business validation:
def Message processData(Message message) {
def body = message.getBody(String)
def xml = new XmlSlurper().parseText(body)
def quantity = xml.Item.Quantity.text() as Integer
def material = xml.Item.Material.text()
// Custom business validation
if (quantity <= 0) {
throw new Exception("Invalid quantity ${quantity} for material ${material}. Quantity must be positive.")
}
if (material.isEmpty()) {
throw new Exception("Material number is required but was empty.")
}
return message
}
The exception message text appears in the MPL and is accessible as ${exception.message} in the Exception Sub-Process — include all relevant data in it.
Logging from Scripts
Use CPI's logging API to write custom log entries visible in the MPL detail view:
import com.sap.gateway.ip.core.customdev.util.Message
import java.util.logging.Logger
def Message processData(Message message) {
def log = Logger.getLogger("YourIFlowName")
def props = message.getProperties()
def orderID = props.get("OrderID")
log.info("Processing order: " + orderID)
// ... processing logic ...
log.info("Order " + orderID + " processed successfully")
return message
}
Log entries appear in the MPL trace view. Use log.info() for normal progress messages. Use log.warning() for unexpected-but-handled situations. Logging at the right granularity saves hours of debugging — too few logs make problems hard to trace; too many logs bury the relevant entries in noise.
Working with JSON in Groovy
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
def Message processData(Message message) {
def body = message.getBody(String)
// Parse JSON
def json = new JsonSlurper().parseText(body)
// Access fields
def customerName = json.customer.name
def orderTotal = json.order.total as Double
// Apply 10% discount
json.order.discountedTotal = orderTotal * 0.9
// Add a new field
json.processingNote = "Discount applied by CPI"
// Serialize back
message.setBody(JsonOutput.toJson(json))
return message
}
Script Best Practices
- Keep scripts short and focused — one script does one specific task. If a script grows beyond 50 lines, consider splitting it or using a Local Integration Process.
- Always handle null values — check that properties and headers exist before using them. Null pointer exceptions are the most common script bug.
- Include meaningful log statements at script entry and exit and at key decision points.
- Test scripts with the CPI simulation feature before deploying to a live iFlow.
- Add comments explaining why the logic works the way it does, not just what it does.
- Never hard-code credentials, URLs, or environment-specific values in scripts. Read them from exchange properties or externalized parameters instead.
JavaScript as an Alternative
CPI also supports JavaScript (ECMAScript 5) as an alternative scripting language. The Message API is identical — only the syntax differs. Teams already comfortable with JavaScript can use it instead of Groovy. The choice between Groovy and JavaScript is a team preference decision; both have full access to the same CPI scripting API.
