Skip to content

Commit c33f8ef

Browse files
mcruzdevfjtirado
andauthored
Add support for Run.script (Javascript) (#962)
* Introduce Run.script task with JavaScript Signed-off-by: Matheus Cruz <[email protected]> * Introduce Run.script task with JavaScript Signed-off-by: Matheus Cruz <[email protected]> * Structure changes Signed-off-by: fjtirado <[email protected]> * Adjusting poms Signed-off-by: fjtirado <[email protected]> * Adjusting poms #2 Signed-off-by: fjtirado <[email protected]> --------- Signed-off-by: Matheus Cruz <[email protected]> Signed-off-by: fjtirado <[email protected]> Co-authored-by: fjtirado <[email protected]> Co-authored-by: Francisco Javier Tirado Sarti <[email protected]>
1 parent 002b274 commit c33f8ef

File tree

20 files changed

+745
-4
lines changed

20 files changed

+745
-4
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.impl.executors;
17+
18+
import io.serverlessworkflow.api.types.RunScript;
19+
import io.serverlessworkflow.api.types.RunTaskConfiguration;
20+
import io.serverlessworkflow.api.types.Script;
21+
import io.serverlessworkflow.api.types.ScriptUnion;
22+
import io.serverlessworkflow.impl.TaskContext;
23+
import io.serverlessworkflow.impl.WorkflowApplication;
24+
import io.serverlessworkflow.impl.WorkflowContext;
25+
import io.serverlessworkflow.impl.WorkflowDefinition;
26+
import io.serverlessworkflow.impl.WorkflowModel;
27+
import io.serverlessworkflow.impl.WorkflowUtils;
28+
import io.serverlessworkflow.impl.WorkflowValueResolver;
29+
import io.serverlessworkflow.impl.resources.ResourceLoaderUtils;
30+
import io.serverlessworkflow.impl.scripts.ScriptContext;
31+
import io.serverlessworkflow.impl.scripts.ScriptLanguageId;
32+
import io.serverlessworkflow.impl.scripts.ScriptRunner;
33+
import java.util.Map;
34+
import java.util.Objects;
35+
import java.util.Optional;
36+
import java.util.ServiceLoader;
37+
import java.util.concurrent.CompletableFuture;
38+
39+
public class RunScriptExecutor implements RunnableTask<RunScript> {
40+
41+
private Optional<WorkflowValueResolver<Map<String, Object>>> environmentExpr;
42+
43+
private Optional<WorkflowValueResolver<Map<String, Object>>> argumentExpr;
44+
45+
private WorkflowValueResolver<String> codeSupplier;
46+
private boolean isAwait;
47+
private RunTaskConfiguration.ProcessReturnType returnType;
48+
private ScriptRunner taskRunner;
49+
50+
@Override
51+
public void init(RunScript taskConfiguration, WorkflowDefinition definition) {
52+
ScriptUnion scriptUnion = taskConfiguration.getScript();
53+
Script script = scriptUnion.get();
54+
ScriptLanguageId language = ScriptLanguageId.from(script.getLanguage());
55+
56+
this.taskRunner =
57+
ServiceLoader.load(ScriptRunner.class).stream()
58+
.map(ServiceLoader.Provider::get)
59+
.filter(s -> s.identifier().equals(language))
60+
.findFirst()
61+
.orElseThrow(
62+
() ->
63+
new IllegalStateException(
64+
"No script runner implementation found for language " + language));
65+
66+
this.isAwait = taskConfiguration.isAwait();
67+
68+
this.returnType = taskConfiguration.getReturn();
69+
70+
WorkflowApplication application = definition.application();
71+
this.environmentExpr =
72+
script.getEnvironment() != null && script.getEnvironment().getAdditionalProperties() != null
73+
? Optional.of(
74+
WorkflowUtils.buildMapResolver(
75+
application, null, script.getEnvironment().getAdditionalProperties()))
76+
: Optional.empty();
77+
78+
this.argumentExpr =
79+
script.getArguments() != null && script.getArguments().getAdditionalProperties() != null
80+
? Optional.of(
81+
WorkflowUtils.buildMapResolver(
82+
application, null, script.getArguments().getAdditionalProperties()))
83+
: Optional.empty();
84+
85+
this.codeSupplier =
86+
scriptUnion.getInlineScript() != null
87+
? WorkflowUtils.buildStringFilter(application, scriptUnion.getInlineScript().getCode())
88+
: (w, t, m) ->
89+
definition
90+
.resourceLoader()
91+
.load(
92+
Objects.requireNonNull(
93+
scriptUnion.getExternalScript(),
94+
"External script is required if inline script was not set")
95+
.getSource(),
96+
ResourceLoaderUtils::readString,
97+
w,
98+
t,
99+
m);
100+
}
101+
102+
@Override
103+
public CompletableFuture<WorkflowModel> apply(
104+
WorkflowContext workflowContext, TaskContext taskContext, WorkflowModel input) {
105+
return CompletableFuture.supplyAsync(
106+
() ->
107+
taskRunner.runScript(
108+
new ScriptContext(
109+
argumentExpr
110+
.map(m -> m.apply(workflowContext, taskContext, input))
111+
.orElse(Map.of()),
112+
environmentExpr
113+
.map(m -> m.apply(workflowContext, taskContext, input))
114+
.orElse(Map.of()),
115+
codeSupplier.apply(workflowContext, taskContext, input),
116+
isAwait,
117+
returnType),
118+
workflowContext,
119+
taskContext,
120+
input));
121+
}
122+
123+
@Override
124+
public boolean accept(Class<? extends RunTaskConfiguration> clazz) {
125+
return RunScript.class.equals(clazz);
126+
}
127+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.impl.scripts;
17+
18+
import io.serverlessworkflow.api.types.RunTaskConfiguration;
19+
import java.util.Map;
20+
21+
public record ScriptContext(
22+
Map<String, Object> args,
23+
Map<String, Object> envs,
24+
String code,
25+
boolean isAwait,
26+
RunTaskConfiguration.ProcessReturnType returnType) {}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.impl.scripts;
17+
18+
import java.util.Arrays;
19+
20+
public enum ScriptLanguageId {
21+
JS("js"),
22+
PYTHON("python");
23+
24+
private final String lang;
25+
26+
ScriptLanguageId(String lang) {
27+
this.lang = lang;
28+
}
29+
30+
public String getLang() {
31+
return lang;
32+
}
33+
34+
public static ScriptLanguageId from(String lang) {
35+
for (ScriptLanguageId l : ScriptLanguageId.values()) {
36+
if (l.getLang().equalsIgnoreCase(lang)) {
37+
return l;
38+
}
39+
}
40+
throw new IllegalStateException(
41+
"Unsupported script language: "
42+
+ lang
43+
+ ". Supported languages are: "
44+
+ Arrays.toString(
45+
Arrays.stream(ScriptLanguageId.values()).map(ScriptLanguageId::getLang).toArray()));
46+
}
47+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.impl.scripts;
17+
18+
import io.serverlessworkflow.impl.ServicePriority;
19+
import io.serverlessworkflow.impl.TaskContext;
20+
import io.serverlessworkflow.impl.WorkflowContext;
21+
import io.serverlessworkflow.impl.WorkflowModel;
22+
import io.serverlessworkflow.impl.executors.RunScriptExecutor;
23+
24+
/** Represents a script task that executes a script in a specific scripting language. */
25+
public interface ScriptRunner extends ServicePriority {
26+
27+
/**
28+
* The scripting language supported by this script task runner.
29+
*
30+
* @return the scripting language as {@link RunScriptExecutor.LanguageId} enum.
31+
*/
32+
ScriptLanguageId identifier();
33+
34+
WorkflowModel runScript(
35+
ScriptContext script,
36+
WorkflowContext workflowContext,
37+
TaskContext taskContext,
38+
WorkflowModel input);
39+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
io.serverlessworkflow.impl.executors.RunWorkflowExecutor
2-
io.serverlessworkflow.impl.executors.RunShellExecutor
2+
io.serverlessworkflow.impl.executors.RunShellExecutor
3+
io.serverlessworkflow.impl.executors.RunScriptExecutor

impl/pom.xml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<version.org.glassfish.jersey>3.1.11</version.org.glassfish.jersey>
1717
<version.com.cronutils>9.2.1</version.com.cronutils>
1818
<version.docker.java>3.6.0</version.docker.java>
19+
<version.org.graalvm.polyglot>23.1.1</version.org.graalvm.polyglot>
1920
</properties>
2021
<dependencyManagement>
2122
<dependencies>
@@ -130,12 +131,17 @@
130131
<groupId>com.h2database</groupId>
131132
<artifactId>h2-mvstore</artifactId>
132133
<version>${version.com.h2database}</version>
133-
</dependency>
134-
<dependency>
134+
</dependency>
135+
<dependency>
136+
<groupId>io.serverlessworkflow</groupId>
137+
<artifactId>serverlessworkflow-impl-script-js</artifactId>
138+
<version>${project.version}</version>
139+
</dependency>
140+
<dependency>
135141
<groupId>com.cronutils</groupId>
136142
<artifactId>cron-utils</artifactId>
137143
<version>${version.com.cronutils}</version>
138-
</dependency>
144+
</dependency>
139145
<dependency>
140146
<groupId>com.github.docker-java</groupId>
141147
<artifactId>docker-java-core</artifactId>
@@ -146,6 +152,17 @@
146152
<artifactId>docker-java-transport-httpclient5</artifactId>
147153
<version>${version.docker.java}</version>
148154
</dependency>
155+
<dependency>
156+
<groupId>org.graalvm.polyglot</groupId>
157+
<artifactId>js</artifactId>
158+
<version>${version.org.graalvm.polyglot}</version>
159+
<type>pom</type>
160+
</dependency>
161+
<dependency>
162+
<groupId>org.graalvm.polyglot</groupId>
163+
<artifactId>polyglot</artifactId>
164+
<version>${version.org.graalvm.polyglot}</version>
165+
</dependency>
149166
</dependencies>
150167
</dependencyManagement>
151168
<modules>
@@ -163,5 +180,6 @@
163180
<module>validation</module>
164181
<module>container</module>
165182
<module>test</module>
183+
<module>script-js</module>
166184
</modules>
167185
</project>

impl/script-js/pom.xml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<modelVersion>4.0.0</modelVersion>
3+
<parent>
4+
<groupId>io.serverlessworkflow</groupId>
5+
<artifactId>serverlessworkflow-impl</artifactId>
6+
<version>8.0.0-SNAPSHOT</version>
7+
</parent>
8+
<artifactId>serverlessworkflow-impl-script-js</artifactId>
9+
<name>Serverless Workflow :: Impl :: Script JavaScript</name>
10+
<dependencies>
11+
<dependency>
12+
<groupId>io.serverlessworkflow</groupId>
13+
<artifactId>serverlessworkflow-impl-core</artifactId>
14+
</dependency>
15+
<dependency>
16+
<groupId>org.graalvm.polyglot</groupId>
17+
<artifactId>polyglot</artifactId>
18+
</dependency>
19+
<dependency>
20+
<groupId>org.graalvm.polyglot</groupId>
21+
<artifactId>js</artifactId>
22+
<type>pom</type>
23+
</dependency>
24+
</dependencies>
25+
</project>

0 commit comments

Comments
 (0)