14 KiB
Scripting - Comprehensive Reference
Source: SAP BTP Integration Suite Documentation Documentation: https://github.com/SAP-docs/sap-btp-integration-suite/tree/main/docs/ci/Development Last Updated: 2025-11-22
Table of Contents
- Overview
- Groovy Scripting
- JavaScript Scripting
- Script Collections
- Common Use Cases
- Best Practices
- API Reference
Overview
SAP Cloud Integration supports two scripting languages:
- Groovy (primary, full API support)
- JavaScript (limited API support)
When to Use Scripts:
- Custom transformations not possible with standard steps
- Complex business logic
- Access to external libraries (Groovy)
- Dynamic routing decisions
When NOT to Use Scripts:
- Standard transformations (use Content Modifier, Mapping)
- Simple XML/JSON manipulation (use XPath, JSONPath)
- Standard encoding/decoding (use Encoder/Decoder steps)
Documentation: https://github.com/SAP-docs/sap-btp-integration-suite/blob/main/docs/ci/Development/general-scripting-guidelines-fcbf0f2.md
Groovy Scripting
Basic Structure
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
// Your code here
return message
}
Accessing Message Components
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
// Get message body as String
def body = message.getBody(String.class)
// Get message body as InputStream (for large payloads)
def bodyStream = message.getBody(java.io.InputStream.class)
// Get specific header
def contentType = message.getHeader("Content-Type", String.class)
// Get all headers as Map
def headers = message.getHeaders()
// Get exchange property
def prop = message.getProperty("PropertyName")
// Get all properties
def props = message.getProperties()
return message
}
Modifying Message Components
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
// Set body
message.setBody("New body content")
// Set body from object
def data = [name: "John", age: 30]
message.setBody(groovy.json.JsonOutput.toJson(data))
// Set header
message.setHeader("X-Custom-Header", "value")
// Set property
message.setProperty("CustomProperty", "value")
return message
}
XML Processing
import com.sap.gateway.ip.core.customdev.util.Message
import groovy.xml.XmlSlurper
import groovy.xml.MarkupBuilder
def Message processData(Message message) {
// Parse XML body (use parse for streams, not parseText)
def body = message.getBody(java.io.InputStream.class)
def xml = new XmlSlurper().parse(body)
// Access elements
def name = xml.customer.name.text()
def id = xml.customer.@id.text() // attribute
// Iterate over elements
xml.items.item.each { item ->
println "Item: ${item.name.text()}"
}
// Create new XML
def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
builder.response {
status("success")
data(name)
}
message.setBody(writer.toString())
return message
}
JSON Processing
import com.sap.gateway.ip.core.customdev.util.Message
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
def Message processData(Message message) {
// Parse JSON body
def body = message.getBody(String.class)
def json = new JsonSlurper().parseText(body)
// Access properties
def name = json.customer.name
def items = json.items
// Modify JSON
json.customer.processed = true
json.timestamp = new Date().format("yyyy-MM-dd'T'HH:mm:ss")
// Convert back to JSON string
message.setBody(JsonOutput.toJson(json))
// Pretty print (avoid in production - performance impact)
// message.setBody(JsonOutput.prettyPrint(JsonOutput.toJson(json)))
return message
}
Logging
import com.sap.gateway.ip.core.customdev.util.Message
import org.slf4j.LoggerFactory
def Message processData(Message message) {
def log = LoggerFactory.getLogger("script.processing")
log.info("Processing started")
log.debug("Body: ${message.getBody(String.class)}")
log.warn("Warning message")
log.error("Error occurred", new Exception("Details"))
return message
}
Secure Parameters
import com.sap.gateway.ip.core.customdev.util.Message
import com.sap.it.api.ITApiFactory
import com.sap.it.api.securestore.SecureStoreService
def Message processData(Message message) {
def secureStore = ITApiFactory.getService(SecureStoreService.class, null)
def credential = secureStore.getUserCredential("CredentialName")
def username = credential.getUsername()
def password = new String(credential.getPassword())
return message
}
Value Mappings
import com.sap.gateway.ip.core.customdev.util.Message
import com.sap.it.api.ITApiFactory
import com.sap.it.api.mapping.ValueMappingApi
def Message processData(Message message) {
def vmApi = ITApiFactory.getService(ValueMappingApi.class, null)
def targetValue = vmApi.getMappedValue(
"SourceAgency", // source agency
"SourceIdentifier", // source identifier
"SourceValue", // source value
"TargetAgency", // target agency
"TargetIdentifier" // target identifier
)
return message
}
Attachments
import com.sap.gateway.ip.core.customdev.util.Message
import javax.activation.DataHandler
def Message processData(Message message) {
// Get all attachments
def attachments = message.getAttachments()
// Get specific attachment
def attachment = message.getAttachment("filename.pdf")
if (attachment) {
def content = attachment.getContent()
}
// Add attachment
def data = "Attachment content".getBytes()
def dataSource = new javax.mail.util.ByteArrayDataSource(data, "text/plain")
message.addAttachmentObject("newfile.txt", new DataHandler(dataSource))
return message
}
JavaScript Scripting
Basic Structure
function processData(message) {
// Your code here
return message;
}
Accessing Message
function processData(message) {
// Get body
var body = message.getBody(java.lang.String);
// Get header
var header = message.getHeader("Content-Type", java.lang.String);
// Get property
var prop = message.getProperty("PropertyName");
// Set body
message.setBody("New content");
// Set header
message.setHeader("X-Custom", "value");
return message;
}
JSON Processing
function processData(message) {
var body = message.getBody(java.lang.String);
var json = JSON.parse(body);
// Modify
json.processed = true;
message.setBody(JSON.stringify(json));
return message;
}
Note: JavaScript has limited API support compared to Groovy.
Script Collections
Reusable script libraries deployed as artifacts.
Creating Script Collection
- Create Script Collection artifact
- Add script files (.groovy or .gsh)
- Deploy to tenant
Structure
ScriptCollection/
├── META-INF/
│ └── MANIFEST.MF
└── script/
├── Utils.groovy
├── Validators.groovy
└── Transformers.groovy
Using in Integration Flow
- Add Script Collection reference in Resources
- Import and use in Script step:
import com.company.Utils
def Message processData(Message message) {
def result = Utils.processData(message.getBody(String.class))
message.setBody(result)
return message
}
Documentation: https://github.com/SAP-docs/sap-btp-integration-suite/blob/main/docs/ci/Development/creating-a-script-collection-824bff0.md
Common Use Cases
Dynamic Routing
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
def body = message.getBody(String.class)
def json = new groovy.json.JsonSlurper().parseText(body)
def endpoint
switch(json.region) {
case "US":
endpoint = "[https://us-api.example.com"](https://us-api.example.com")
break
case "EU":
endpoint = "[https://eu-api.example.com"](https://eu-api.example.com")
break
default:
endpoint = "[https://default-api.example.com"](https://default-api.example.com")
}
message.setProperty("TargetEndpoint", endpoint)
return message
}
Add Timestamp
import com.sap.gateway.ip.core.customdev.util.Message
import java.time.Instant
def Message processData(Message message) {
message.setHeader("X-Timestamp", Instant.now().toString())
message.setProperty("ProcessingTime", new Date())
return message
}
UUID Generation
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
def uuid = java.util.UUID.randomUUID().toString()
message.setHeader("X-Correlation-ID", uuid)
return message
}
Base64 Encoding/Decoding
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
def body = message.getBody(String.class)
// Encode
def encoded = body.bytes.encodeBase64().toString()
// Decode
def decoded = new String(encoded.decodeBase64())
message.setBody(encoded)
return message
}
Exception Handling
import com.sap.gateway.ip.core.customdev.util.Message
import org.slf4j.LoggerFactory
def Message processData(Message message) {
def log = LoggerFactory.getLogger("script")
try {
def body = message.getBody(String.class)
def json = new groovy.json.JsonSlurper().parseText(body)
// Process...
} catch (Exception e) {
log.error("Processing failed: ${e.message}", e)
message.setProperty("ErrorMessage", e.message)
throw e // Re-throw to trigger error handling
}
return message
}
Best Practices
Do
-
Use SLF4J for logging
def log = LoggerFactory.getLogger("script") log.info("Message") -
Use streams for large payloads
def body = message.getBody(java.io.InputStream.class) def xml = new XmlSlurper().parse(body) -
Use StringBuilder for string concatenation
def sb = new StringBuilder() items.each { sb.append(it) } -
Include comments
// Transform customer data to target format // Input: JSON with customer array // Output: XML with customer elements -
Use credential artifacts
def secureStore = ITApiFactory.getService(SecureStoreService.class, null) def cred = secureStore.getUserCredential("MyCredential")
Don't
-
Don't use parseText() for large XML
// BAD: Loads entire string into memory def xml = new XmlSlurper().parseText(bodyString) // GOOD: Stream-based parsing def xml = new XmlSlurper().parse(bodyStream) -
Don't write credentials to headers
// BAD: Exposed in traces message.setHeader("Authorization", "Bearer " + token) // GOOD: Use adapter authentication -
Don't use TimeZone.setDefault()
- Affects entire JVM
- Not thread-safe
- Use explicit timezone in formatting
-
Don't use Eval class
- Never unloaded from memory
- Performance and security issues
-
Don't bind variables unnecessarily
- Persists in memory
- Not thread-safe
- Causes memory leaks
Documentation: https://github.com/SAP-docs/sap-btp-integration-suite/blob/main/docs/ci/Development/general-scripting-guidelines-fcbf0f2.md
API Reference
Message API
| Method | Description |
|---|---|
getBody(Class) |
Get body as specified type |
setBody(Object) |
Set message body |
getHeader(name, Class) |
Get specific header |
getHeaders() |
Get all headers as Map |
setHeader(name, value) |
Set header |
getProperty(name) |
Get property |
getProperties() |
Get all properties |
setProperty(name, value) |
Set property |
getAttachments() |
Get all attachments |
getAttachment(name) |
Get specific attachment |
addAttachmentObject(name, DataHandler) |
Add attachment |
Available Services
| Service | Purpose |
|---|---|
SecureStoreService |
Access credentials |
ValueMappingApi |
Value mapping lookups |
PartnerDirectoryService |
Partner directory access |
DataStoreService |
Data store operations |
Import Package
import com.sap.gateway.ip.core.customdev.util.Message
import com.sap.it.api.ITApiFactory
import com.sap.it.api.securestore.SecureStoreService
import com.sap.it.api.mapping.ValueMappingApi
import org.slf4j.LoggerFactory
Related Documentation
- Scripting Guidelines: https://github.com/SAP-docs/sap-btp-integration-suite/blob/main/docs/ci/Development/general-scripting-guidelines-fcbf0f2.md
- Script Collections: https://github.com/SAP-docs/sap-btp-integration-suite/blob/main/docs/ci/Development/creating-a-script-collection-824bff0.md
- Script Use Cases: https://github.com/SAP-docs/sap-btp-integration-suite/blob/main/docs/ci/Development/script-use-cases-148851b.md
- Access Headers/Properties: https://github.com/SAP-docs/sap-btp-integration-suite/blob/main/docs/ci/Development/access-headers-and-properties-in-scripts-6bc5ed1.md