Common Script Examples

The following chapter shows examples that can be used in any XDM script, that supports JavaScript or Groovy.

Executing a SQL Query

To access a database a JDBC connection is required. XDM offers parameters of type Connection for example a task stage hook parameter or a custom parameter which wrap a JDBC connection. Using the property jdbcConnection on the XDM connection object accesses the required JDBC connection.

A parameter of type connection is required. In this example the variable name of this parameter is connection.

  • Groovy

  • JavaScript

import groovy.sql.Sql;
def query = 'SELECT "Description" FROM "SCHEMA"."TABLE_1"'
Sql sql = new Sql(taskStageHook.connection.jdbcConnection)
sql.eachRow(query, {
    println("Output option 1: ${it.getString(1)}")
    println("Output option 2: ${it[0]}")
    println("Output option 3: ${it.Description}")
})

Find more information in the documentation on the Groovy SQL API

There are three different ways to access the column values:

  1. The first way is via the method getString(<columnIndex>) . This column index starts with 1.

  2. The second way is via the column index directly. Then the index starts with 0 because it is an array.

  3. The third way is via the column name.

    The it within the code is an implicit-created loop variable for the method eachRow().
importPackage(java.sql);
var query = 'SELECT "Description" FROM "SCHEMA"."TABLE_1"';
var prepareStatement = taskStageHook.myConnection.jdbcConnection.prepareStatement(query);
var resultSet = prepareStatement.executeQuery();
while(resultSet.next()) {
    print("Output option 1: " + resultSet.getString(1));
    print("Output option 2: " + resultSet.getString("Description"));
}

resultSet.close();
prepareStatement.close();

This example is built upon the Java JDBC API.

There are two different ways to access the column values:

  1. The first way is via the method getString(<columnIndex>) . This column index starts with 1.

  2. The second way is via the column name.

Calling a REST API

It is possible to call an external service from XDM scripts via a REST API.

As the Spring RestTemplate API is part of the XDM runtime environment, calling a REST API using the Spring library is a convenient way. Also, for many special requirements in authentication, certificates, using HTTP proxies etc. a solution can be implemented.

There is also a ModificationContext API method callRestEndpoint, which also relies on RestTemplate. This can be used for basic requirements. But typically, the approach to use RestTemplate directly allows to meet advanced requirements in a more convenient way.

This example calls a public REST API genderize.io, which gives an evaluation on the gender of a given name.

  • Groovy

  • JavaScript

import groovy.json.JsonSlurper
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpEntity
import org.springframework.http.HttpMethod
import org.springframework.web.client.RestTemplate

def body = restCall("https://api.genderize.io/?name=john", "GET", null,
       [
           "Content-Type": "application/json",
           "Accept": "application/json",
       ]
    )
 print(body)
 var result = new JsonSlurper().parseText(body)
 print("The name  ${result.name} is with a probability of ${result.probability} of gender ${result.gender}")


def restCall(url, method, payload, headersMap) {

    def headers = new HttpHeaders()
    headersMap.each { entry ->
        headers.set(entry.key, entry.value)
    }

    def entity = new HttpEntity(payload, headers)
    println("Call REST Endpoint $url method: $method")

    def restTemplate = buildRestTemplate()
    def response = restTemplate.exchange(url, HttpMethod.valueOf(method), entity, String.class)

    return response.getBody()
}

def buildRestTemplate() {
    return new RestTemplate()
}
importClass(org.springframework.http.HttpHeaders)
importClass(org.springframework.http.HttpEntity)
importClass(org.springframework.http.HttpMethod)
importClass(org.springframework.web.client.RestTemplate)

var body = restCall("https://api.genderize.io/?name=john", "GET", null,
            {
                "Content-Type": "application/json",
                "Accept": "application/json",
            }
        );
print("Raw REST result:" + body);
var result = JSON.parse(body);
print("The name " + result.name + " is with a probability of " + result.probability + " of gender " + result.gender);

function restCall(url, method, payload, headersMap) {
    var headers = new HttpHeaders()

    for(var key in headersMap) {
        headers.set(key, headersMap[key]);
    }
    var entity = new HttpEntity(payload, headers)
    print("Call REST Endpoint " + url + " with method: " + method)

    var restTemplate = buildRestTemplate();
    var response = restTemplate.exchange(url, HttpMethod.valueOf(method), entity, Packages.java.lang.String.class)

    return response.getBody()
}

function buildRestTemplate() {
    return new RestTemplate();
}

Using an HTTP Proxy

If there are additional requirements on the HTTP connection to be established, this can be achieved by configuring the setup of the RestTemplate. For example, to use an HTTP Proxy use the following buildRestTemplate Method:

  • Groovy

  • JavaScript

//[...]
// add the following imports
import org.springframework.http.client.SimpleClientHttpRequestFactory
import java.net.Proxy.Type

//[...]

def buildRestTemplate() {
    def requestFactory = new SimpleClientHttpRequestFactory()

    def proxy = new Proxy(Type.HTTP, new InetSocketAddress("my.proxy.com", 8080))
    requestFactory.setProxy(proxy)

    return new RestTemplate(requestFactory)
}
//[...]
// add the following imports:
importClass(org.springframework.http.client.SimpleClientHttpRequestFactory)
importClass(java.net.Proxy.Type)

function buildRestTemplate() {
    var requestFactory = new SimpleClientHttpRequestFactory();

    var proxy = new Proxy(Type.HTTP, new InetSocketAddress("my.proxy.com", 8080));
    requestFactory.setProxy(proxy);

    return new RestTemplate(requestFactory);
}

Authentication with an XDM credential

It is also possible to use an XDM credential as a parameter and set up HTTP Basic authentication for the REST call:

  • Groovy

  • JavaScript

//[...]

def auth = new String(credential.user + ':' + credential.password).bytes.encodeBase64().toString()
var body = restCall("https://api.genderize.io/?name=" + firstname, "GET", null,
     {
         "Content-Type": "application/json",
         "Accept": "application/json",
         "Authentication": "Basic " + auth,
     }
)
print("Raw REST result:" + body)
var result = JSON.parse(body)
print("The name " + result.name + " is with a probability of " + result.probability + " of gender " + result.gender)
//[...]
var auth = new String(credential.user + ':' + credential.password).bytes.encodeBase64().toString()
var body = restCall("https://api.genderize.io/?name=" + firstname, "GET", null,
    {
        "Content-Type": "application/json",
        "Accept": "application/json",
        "Authentication": "Basic " + auth,
    }
);
print("Raw REST result:" + body);
var result = JSON.parse(body);
print("The name " + result.name + " is with a probability of " + result.probability + " of gender " + result.gender);

Doing a REST POST request

The restCall method described above can also be used to perform a POST request on a REST API:

  • Groovy

  • JavaScript

//[...]
def payload = [
"myKey": "myValue",
"myOtherKey": 12,
]
def body = restCall("https://echo.zuplo.io/", "POST", JsonOutput.toJson(payload),
[
"Content-Type": "application/json",
"Accept": "application/json",
]
)
//[...]
//[...]
var payload = {
    "myKey": "myValue",
    "myOtherKey": 12,
}
var body = restCall("https://echo.zuplo.io/", "POST", JSON.stringify(payload),
    {
        "Content-Type": "application/json",
        "Accept": "application/json",
    }
);
//[...]

Send an e-mail after an execution finished

Each time a data shop is executed, a dedicated user should receive an email asking for review.

For many use cases it is useful to send a notification email when an XDM execution has finished. This can be a task, a workflow, or a data shop order that should be reviewed by a dedicated user.

The following code sends an email to a specific user, with the SMTP server configured in the script. Authentication is required for the SMTP server, and the user for this authentication is read from the defined XDM credential. The user with the display name SMTP User is used. This credential must contain the SMTP user name (typically the sender’s e-mail address) and the corresponding SMTP password of this account.

The script requires the external Java libraries Angus Mail Default Provider and Jakarta Activation.

Both can be downloaded below: * Angus Mail Default Provider * Jakarta Activation

The JAR files have to be uploaded in XDM to use them. In the XDM user interface, open Configuration → Files. Create one XDM file object for each downloaded JAR Set the file type to JAVA library and upload the JAR file. Add both XDM files as libraries to the XDM object that executes the script (for example the workflow, event hook, or task template):
  • Groovy

import jakarta.mail.*
import jakarta.mail.internet.*


def from = "John.Doe@example.com"
def to = "jane.doe@example.com"
def subject = "Executed task info"
def content = """
    This is a example
    """

def smtpHost = "Example-Mail.host"
def smtpPort = 587
def smtpCredential = api.credentials.find{c -> c.displayName == 'SMTP User'} // <--- Credential Here

// Setup internal properties
def props = [
    "mail.smtp.user": smtpCredential.user,
    "mail.smtp.host": smtpHost,
    "mail.smtp.port": smtpPort,
    "mail.smtp.starttls.enable": true,
    "mail.smtp.socketFactory.class": "javax.net.ssl.SSLSocketFactory",
    "mail.smtp.ssl.trust": smtpHost
]

// Setup the message.
def message = new MimeMessage(Session.getDefaultInstance(new Properties(props)))
message.setFrom(new InternetAddress(from))
message.addRecipients(Message.RecipientType.TO, new InternetAddress(to))
message.setSubject(subject)
message.setContent(content.toString(), "text/plain")

// Send the mail.
Transport.send(message, smtpCredential.user, smtpCredential.password)