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

563 lines
14 KiB
Markdown

# Scripting - Comprehensive Reference
**Source**: SAP BTP Integration Suite Documentation
**Documentation**: [https://github.com/SAP-docs/sap-btp-integration-suite/tree/main/docs/ci/Development](https://github.com/SAP-docs/sap-btp-integration-suite/tree/main/docs/ci/Development)
**Last Updated**: 2025-11-22
---
## Table of Contents
1. [Overview](#overview)
2. [Groovy Scripting](#groovy-scripting)
3. [JavaScript Scripting](#javascript-scripting)
4. [Script Collections](#script-collections)
5. [Common Use Cases](#common-use-cases)
6. [Best Practices](#best-practices)
7. [API Reference](#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](https://github.com/SAP-docs/sap-btp-integration-suite/blob/main/docs/ci/Development/general-scripting-guidelines-fcbf0f2.md)
---
## Groovy Scripting
### Basic Structure
```groovy
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
// Your code here
return message
}
```
### Accessing Message Components
```groovy
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
```groovy
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
```groovy
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
```groovy
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
```groovy
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
```groovy
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
```groovy
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
```groovy
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
```javascript
function processData(message) {
// Your code here
return message;
}
```
### Accessing Message
```javascript
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
```javascript
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:
```groovy
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](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
```groovy
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
```groovy
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
```groovy
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
```groovy
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
```groovy
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**
```groovy
def log = LoggerFactory.getLogger("script")
log.info("Message")
```
2. **Use streams for large payloads**
```groovy
def body = message.getBody(java.io.InputStream.class)
def xml = new XmlSlurper().parse(body)
```
3. **Use StringBuilder for string concatenation**
```groovy
def sb = new StringBuilder()
items.each { sb.append(it) }
```
4. **Include comments**
```groovy
// Transform customer data to target format
// Input: JSON with customer array
// Output: XML with customer elements
```
5. **Use credential artifacts**
```groovy
def secureStore = ITApiFactory.getService(SecureStoreService.class, null)
def cred = secureStore.getUserCredential("MyCredential")
```
### Don't
1. **Don't use parseText() for large XML**
```groovy
// 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**
```groovy
// 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](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
```groovy
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](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](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](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](https://github.com/SAP-docs/sap-btp-integration-suite/blob/main/docs/ci/Development/access-headers-and-properties-in-scripts-6bc5ed1.md)