From 9f854ea032b77810c19aed40cc5db4ef512cd9c9 Mon Sep 17 00:00:00 2001 From: Markus Perndorfer Date: Tue, 1 Dec 2020 11:54:35 +0100 Subject: [PATCH] add scripts --- .gitignore | 3 + .java-version | 1 + README.md | 34 +++++++++ bootstrap.sh | 18 +++++ execute.groovy | 38 ++++++++++ impl/MessageImpl.groovy | 116 ++++++++++++++++++++++++++++++ impl/MessageLogFactoryImpl.groovy | 12 ++++ impl/MessageLogImpl.groovy | 68 ++++++++++++++++++ run.sh | 3 + script.groovy | 12 ++++ 10 files changed, 305 insertions(+) create mode 100644 .gitignore create mode 100644 .java-version create mode 100644 README.md create mode 100755 bootstrap.sh create mode 100644 execute.groovy create mode 100644 impl/MessageImpl.groovy create mode 100644 impl/MessageLogFactoryImpl.groovy create mode 100644 impl/MessageLogImpl.groovy create mode 100755 run.sh create mode 100644 script.groovy diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc5d764 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +groovy-*/ +lib/ +apache-groovy-binary-* \ No newline at end of file diff --git a/.java-version b/.java-version new file mode 100644 index 0000000..9d60796 --- /dev/null +++ b/.java-version @@ -0,0 +1 @@ +11 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..140085e --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# scpi-script-executor + +Run your SAP Cloud Platform Integration Groovy scripts on your local machine for easier test and debugging. + +## Prerequites + +- JDK installed and configured (e.g. [SAPMachine][machine])\ + Make sure the environment variable `JAVA_HOME` points to the JDK +- `curl` to download dependencies + +[machine]: https://sap.github.io/SapMachine/ + +## Setup + +1. Clone/download the repo +1. Run `bootstrap.sh` + +## How to use + +1. Copy-paste your script into `script.groovy` +1. Adapt `execute.groovy` to: + - Setup the test message + - Change the log output + - Add assertions + - ... +1. `./run.sh`\ + The first run downloads additional dependencies (cached for subsequent runs). Be patient :wink: + +## Notes + +This project only implements a limited subset of the [Scripting API][api] of SCPI. +Check the classes in the `impl` subfolder for details. + +[api]: https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/LATEST/en-US/c5c7933b77ba46dbaa9a2c1576dbb381.html \ No newline at end of file diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..dc91124 --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env sh + +# ref. https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/LATEST/en-US/03b32eb2c5c249f0a59bcd27c44d1e4e.html +GROOVY_VERSION=2.4.12 +echo "Setting up Groovy runtime $GROOVY_VERSION..." +curl -O "https://archive.apache.org/dist/groovy/$GROOVY_VERSION/distribution/apache-groovy-binary-$GROOVY_VERSION.zip" +unzip -qo apache-groovy-binary*.zip +echo "Setting up Groovy runtime $GROOVY_VERSION... DONE" + +# ref. https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/LATEST/en-US/062f7a7e5c374e67b568dddc7b7844a9.html +echo "Downloading SCPI APIs..." +mkdir -p 'lib' +( + cd lib || exit 1 + curl -O --cookie 'eula_3_1_agreed=tools.hana.ondemand.com/developer-license-3_1.txt' https://tools.hana.ondemand.com/additional/com.sap.it.public.generic.api-2.20.0.jar + curl -O --cookie 'eula_3_1_agreed=tools.hana.ondemand.com/developer-license-3_1.txt' https://tools.hana.ondemand.com/additional/cloud.integration.script.apis-1.36.1.jar +) +echo "Downloading SCPI APIs... DONE" diff --git a/execute.groovy b/execute.groovy new file mode 100644 index 0000000..be421d3 --- /dev/null +++ b/execute.groovy @@ -0,0 +1,38 @@ +@GrabConfig(systemClassLoader=true) +// additonal dependencies required by the Generic API +@Grab(group='org.apache.camel', module='camel-core', version='2.20.4') +@Grab(group='javax.activation', module='activation', version='1.1.1') + +import groovy.json.* +import impl.* + +// setup Groovy scripting engine +def binding = new Binding() +def logFactory = new MessageLogFactoryImpl() +binding.setVariable("messageLogFactory", logFactory) +def shell = new GroovyShell(binding) + +def scriptFile = new File('script.groovy') +shell.evaluate(scriptFile) +def script = shell.parse(scriptFile) + +// setup message +def message = new MessageImpl() +message.headers.foo = "bar" +message.properties.bar = "foo" +message.body = "Hello World" + +// execute script and log output +println "==== BEFORE ====" +println message + +result = script.invokeMethod("processData", message) + +println "" +println "==== AFTER ====" +println result +println "" +println logFactory.messageLog + +// Assert correct result +assert result.body == "Hello World processed" diff --git a/impl/MessageImpl.groovy b/impl/MessageImpl.groovy new file mode 100644 index 0000000..43ffa92 --- /dev/null +++ b/impl/MessageImpl.groovy @@ -0,0 +1,116 @@ +package impl + +import com.sap.gateway.ip.core.customdev.util.Message + +class MessageImpl implements Message { + Map properties = [:] + Map headers = [:] + def body = "" + + void setAttachmentHeader(java.lang.String a, java.lang.String b, org.apache.camel.Attachment c) { + throw new RuntimeException() + } + + long getBodySize() { + -1 + } + + void setAttachmentHeader(java.lang.String a, java.lang.String b, com.sap.gateway.ip.core.customdev.util.AttachmentWrapper c) { + throw new RuntimeException() + } + + void addAttachmentHeader(java.lang.String a, java.lang.String b, com.sap.gateway.ip.core.customdev.util.AttachmentWrapper c) { + throw new RuntimeException() + } + + void setAttachmentWrapperObjects(java.util.Map a) { + throw new RuntimeException() + } + + java.lang.Object getHeader(java.lang.String a, java.lang.Class c) { + throw new RuntimeException() + } + + long getAttachmentsSize() { + throw new RuntimeException() + } + + java.lang.String getAttachmentHeader(java.lang.String a, org.apache.camel.Attachment b) { + throw new RuntimeException() + } + + void addAttachmentObject(java.lang.String a, org.apache.camel.Attachment b) { + throw new RuntimeException() + } + + void setHeader(java.lang.String a, java.lang.Object b) { + throw new RuntimeException() + } + + void removeAttachmentHeader(java.lang.String a, org.apache.camel.Attachment b) { + throw new RuntimeException() + } + + void removeAttachmentHeader(java.lang.String a, com.sap.gateway.ip.core.customdev.util.AttachmentWrapper b) { + throw new RuntimeException() + } + + void addAttachmentObject(java.lang.String a, com.sap.gateway.ip.core.customdev.util.AttachmentWrapper b) { + throw new RuntimeException() + } + + java.util.Map getAttachmentObjects() { + throw new RuntimeException() + } + + java.util.Map getAttachmentWrapperObjects() { + throw new RuntimeException() + } + + void addAttachmentHeader(java.lang.String a, java.lang.String b, org.apache.camel.Attachment c) { + throw new RuntimeException() + } + + java.lang.String getAttachmentHeader(java.lang.String a, com.sap.gateway.ip.core.customdev.util.AttachmentWrapper b) { + throw new RuntimeException() + } + + void setAttachmentObjects(java.util.Map a) { + throw new RuntimeException() + } + + java.util.Map getAttachments() { + throw new RuntimeException() + } + + java.lang.Object getBody(java.lang.Class clazz) { + if (clazz == java.io.InputStream.class) { + InputStream stream = new ByteArrayInputStream(this.body.getBytes("UTF-8")); + return stream + } else if (clazz == java.lang.String.class) { + return body + } else { + throw new RuntimeException("Unsupported class " + clazz) + } + } + + void setAttachments(java.util.Map a) { + throw new RuntimeException() + } + + @Override + String toString() { + def result = "MessageImpl\n" + result += " Properties\n" + properties.each { + result += " - ${it.key} -> ${it.value}\n" + } + result += " Headers\n" + headers.each { + result += " - ${it.key} -> ${it.value}\n" + } + result += " >>> Body\n" + result += " ${body}\n" + result += " <<< Body\n" + } +} \ No newline at end of file diff --git a/impl/MessageLogFactoryImpl.groovy b/impl/MessageLogFactoryImpl.groovy new file mode 100644 index 0000000..d2164b4 --- /dev/null +++ b/impl/MessageLogFactoryImpl.groovy @@ -0,0 +1,12 @@ +package impl + +import com.sap.it.api.msglog.MessageLogFactory +import com.sap.it.api.msglog.MessageLog + +class MessageLogFactoryImpl implements MessageLogFactory { + def messageLog = new MessageLogImpl() + + MessageLog getMessageLog(Object context) { + return messageLog + } +} \ No newline at end of file diff --git a/impl/MessageLogImpl.groovy b/impl/MessageLogImpl.groovy new file mode 100644 index 0000000..cb01185 --- /dev/null +++ b/impl/MessageLogImpl.groovy @@ -0,0 +1,68 @@ +package impl + +import com.sap.it.api.msglog.MessageLog + +class MessageLogImpl implements MessageLog { + def attachments = [] + def headers = [:] + def properties = [:] + + void addAttachmentAsString(String name, String body, String type) { + attachments.add([ + "name": name, + "body": body, + "type": type + ]) + } + + void addCustomHeaderProperty(String name, String value) { + headers[name] = value + } + + void setBooleanProperty(String name, Boolean value) { + properties[name] = value + } + + void setDateProperty(String name, Date value) { + properties[name] = value + } + + void setDoubleProperty(String name, Double value) { + properties[name] = value + } + + void setFloatProperty(String name, Float value) { + properties[name] = value + } + + void setIntegerProperty(String name, Integer value) { + properties[name] = value + } + + void setLongProperty(String name, Long value) { + properties[name] = value + } + + void setStringProperty(String name, String value) { + properties[name] = value + } + + String toString() { + def result = "MessageLogImpl\n" + result += " Properties\n" + properties.each { + result += " - ${it.key} -> ${it.value}" + } + result += " Custom Headers\n" + headers.each { + result += " - ${it.key} -> ${it.value}" + } + result += " Attachments\n" + attachments.sort{ it.name }.each{ + result += " >>>\"${it.name}\" (${it.type})\n" + result += " ${it.body}\n" + result += " <<<\"${it.name}\" (${it.type})\n" + } + return result + } +} \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..65ccf4b --- /dev/null +++ b/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +./groovy-*/bin/groovy -cp './lib/*' execute.groovy "$@" diff --git a/script.groovy b/script.groovy new file mode 100644 index 0000000..7db79ee --- /dev/null +++ b/script.groovy @@ -0,0 +1,12 @@ +import com.sap.gateway.ip.core.customdev.util.Message; + +def Message processData(Message message) { + def body = message.getBody(java.lang.String.class) + message.body = body + " processed" + + def messageLog = messageLogFactory.getMessageLog(message) + messageLog.addAttachmentAsString("Attachment #1", "header: ${message.headers.foo}", "plain/txt") + messageLog.addAttachmentAsString("Attachment #2", message.properties.bar, "plain/txt") + + return message +} \ No newline at end of file