Files
2025-11-30 08:55:05 +08:00

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

  1. Overview
  2. Groovy Scripting
  3. JavaScript Scripting
  4. Script Collections
  5. Common Use Cases
  6. Best Practices
  7. 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

  1. Create Script Collection artifact
  2. Add script files (.groovy or .gsh)
  3. Deploy to tenant

Structure

ScriptCollection/
├── META-INF/
│   └── MANIFEST.MF
└── script/
    ├── Utils.groovy
    ├── Validators.groovy
    └── Transformers.groovy

Using in Integration Flow

  1. Add Script Collection reference in Resources
  2. 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

  1. Use SLF4J for logging

    def log = LoggerFactory.getLogger("script")
    log.info("Message")
    
  2. Use streams for large payloads

    def body = message.getBody(java.io.InputStream.class)
    def xml = new XmlSlurper().parse(body)
    
  3. Use StringBuilder for string concatenation

    def sb = new StringBuilder()
    items.each { sb.append(it) }
    
  4. Include comments

    // Transform customer data to target format
    // Input: JSON with customer array
    // Output: XML with customer elements
    
  5. Use credential artifacts

    def secureStore = ITApiFactory.getService(SecureStoreService.class, null)
    def cred = secureStore.getUserCredential("MyCredential")
    

Don't

  1. 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)
    
  2. Don't write credentials to headers

    // BAD: Exposed in traces
    message.setHeader("Authorization", "Bearer " + token)
    
    // GOOD: Use adapter authentication
    
  3. Don't use TimeZone.setDefault()

    • Affects entire JVM
    • Not thread-safe
    • Use explicit timezone in formatting
  4. Don't use Eval class

    • Never unloaded from memory
    • Performance and security issues
  5. 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