diff --git a/jbpm/jbpm-bpmn2/src/main/java/org/jbpm/bpmn2/xml/GlobalHandler.java b/jbpm/jbpm-bpmn2/src/main/java/org/jbpm/bpmn2/xml/GlobalHandler.java
index b91a7b931d3..6f66de03e55 100755
--- a/jbpm/jbpm-bpmn2/src/main/java/org/jbpm/bpmn2/xml/GlobalHandler.java
+++ b/jbpm/jbpm-bpmn2/src/main/java/org/jbpm/bpmn2/xml/GlobalHandler.java
@@ -18,13 +18,18 @@
  */
 package org.jbpm.bpmn2.xml;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 
 import org.jbpm.compiler.xml.Handler;
 import org.jbpm.compiler.xml.Parser;
 import org.jbpm.compiler.xml.core.BaseAbstractHandler;
+import org.jbpm.process.core.context.variable.Variable;
+import org.jbpm.process.core.context.variable.VariableScope;
+import org.jbpm.process.core.datatype.DataTypeResolver;
 import org.jbpm.workflow.core.impl.WorkflowProcessImpl;
 import org.kie.api.definition.process.Process;
 import org.xml.sax.Attributes;
@@ -53,6 +58,7 @@ public Object start(final String uri,
 
         final String identifier = attrs.getValue("identifier");
         final String type = attrs.getValue("type");
+        process.addImports(Collections.singleton(type));
         emptyAttributeCheck(localName, "identifier", identifier, parser);
         emptyAttributeCheck(localName, "type", type, parser);
 
@@ -63,6 +69,21 @@ public Object start(final String uri,
         }
         map.put(identifier, type);
 
+        VariableScope variableScope = (VariableScope) process.getDefaultContext(VariableScope.VARIABLE_SCOPE);
+        List<Variable> variables = variableScope.getVariables();
+        Variable variable = new Variable();
+        variable.setId(identifier);
+        variable.setType(DataTypeResolver.fromType(type, parser.getClassLoader()));
+        // if name is given use it as variable name instead of id
+        if (identifier != null && identifier.length() > 0) {
+            variable.setName(identifier);
+            variable.setMetaData(identifier, variable.getName());
+        } else {
+            variable.setName(identifier);
+        }
+        variable.setMetaData(identifier, variable.getName());
+        variables.add(variable);
+
         return null;
     }
 
diff --git a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractNodeVisitor.java b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractNodeVisitor.java
index c5cffb2e7b4..e3429dcdbb4 100644
--- a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractNodeVisitor.java
+++ b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractNodeVisitor.java
@@ -20,8 +20,11 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
+import org.jbpm.process.builder.action.ActionCompilerRegistry;
 import org.jbpm.process.core.ContextContainer;
 import org.jbpm.process.core.context.variable.Mappable;
 import org.jbpm.process.core.context.variable.Variable;
@@ -33,6 +36,8 @@
 import org.jbpm.workflow.core.impl.ConnectionImpl;
 import org.jbpm.workflow.core.impl.DataAssociation;
 import org.jbpm.workflow.core.impl.DataDefinition;
+import org.jbpm.workflow.core.impl.DroolsConsequenceAction;
+import org.jbpm.workflow.core.impl.ExtendedNodeImpl;
 import org.jbpm.workflow.core.node.Assignment;
 import org.jbpm.workflow.core.node.HumanTaskNode;
 import org.jbpm.workflow.core.node.StartNode;
@@ -69,6 +74,7 @@
 import static org.jbpm.ruleflow.core.Metadata.HIDDEN;
 import static org.jbpm.ruleflow.core.factory.NodeFactory.METHOD_DONE;
 import static org.jbpm.ruleflow.core.factory.NodeFactory.METHOD_NAME;
+import static org.kie.kogito.internal.utils.ConversionUtils.sanitizeString;
 
 public abstract class AbstractNodeVisitor<T extends Node> extends AbstractVisitor {
 
@@ -79,6 +85,43 @@ public void visitNode(T node, BlockStmt body, VariableScope variableScope, Proce
         if (isAdHocNode(node) && !(node instanceof HumanTaskNode)) {
             metadata.addSignal(node.getName(), null);
         }
+        if (isExtendedNode(node)) {
+            ExtendedNodeImpl extendedNodeImpl = (ExtendedNodeImpl) node;
+            addScript(extendedNodeImpl, body, ON_ACTION_SCRIPT_METHOD, ExtendedNodeImpl.EVENT_NODE_ENTER);
+            addScript(extendedNodeImpl, body, ON_ACTION_SCRIPT_METHOD, ExtendedNodeImpl.EVENT_NODE_EXIT);
+        }
+    }
+
+    private void addScript(ExtendedNodeImpl extendedNodeImpl, BlockStmt body, String factoryMethod, String actionType) {
+        if (!extendedNodeImpl.hasActions(actionType)) {
+            return;
+        }
+        List<DroolsConsequenceAction> scripts = extendedNodeImpl.getActions(actionType).stream()
+                .filter(Predicate.not(Objects::isNull))
+                .filter(DroolsConsequenceAction.class::isInstance)
+                .map(DroolsConsequenceAction.class::cast)
+                .filter(e -> e.getConsequence() != null && !e.getConsequence().isBlank())
+                .toList();
+
+        for (DroolsConsequenceAction script : scripts) {
+            body.addStatement(getFactoryMethod(getNodeId((T) extendedNodeImpl), factoryMethod,
+                    new StringLiteralExpr(actionType),
+                    new StringLiteralExpr(script.getDialect()),
+                    new StringLiteralExpr(sanitizeString(script.getConsequence())),
+                    buildDroolsConsequenceAction(extendedNodeImpl, script.getDialect(), script.getConsequence())));
+            ;
+        }
+    }
+
+    private Expression buildDroolsConsequenceAction(ExtendedNodeImpl extendedNodeImpl, String dialect, String script) {
+        if (script == null) {
+            return new NullLiteralExpr();
+        }
+        return ActionCompilerRegistry.instance().find(dialect).buildAction(extendedNodeImpl, script);
+    }
+
+    private boolean isExtendedNode(T node) {
+        return node instanceof ExtendedNodeImpl;
     }
 
     private boolean isAdHocNode(Node node) {
diff --git a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractVisitor.java b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractVisitor.java
index ce0168cfe0e..17dd3cd9d36 100644
--- a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractVisitor.java
+++ b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/AbstractVisitor.java
@@ -54,8 +54,9 @@
 
 public abstract class AbstractVisitor {
 
+    protected static final String ON_ACTION_SCRIPT_METHOD = "onActionScript";
     protected static final String FACTORY_FIELD_NAME = "factory";
-    protected static final String KCONTEXT_VAR = "kcontext";
+    public static final String KCONTEXT_VAR = "kcontext";
 
     protected MethodCallExpr getWorkflowElementConstructor(WorkflowElementIdentifier identifier) {
         Type type = new ClassOrInterfaceType().setName(WorkflowElementIdentifierFactory.class.getName());
diff --git a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/process/builder/action/ActionCompiler.java b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/process/builder/action/ActionCompiler.java
new file mode 100644
index 00000000000..16f476209a3
--- /dev/null
+++ b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/process/builder/action/ActionCompiler.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jbpm.process.builder.action;
+
+import java.util.Arrays;
+
+import org.jbpm.workflow.core.impl.NodeImpl;
+
+import com.github.javaparser.ast.expr.Expression;
+
+public interface ActionCompiler {
+
+    String[] dialects();
+
+    default boolean accept(String dialect) {
+        return Arrays.asList(dialect).contains(dialect);
+    }
+
+    Expression buildAction(NodeImpl nodeImpl, String scrtip);
+}
diff --git a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/process/builder/action/ActionCompilerRegistry.java b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/process/builder/action/ActionCompilerRegistry.java
new file mode 100644
index 00000000000..9edb3e5d774
--- /dev/null
+++ b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/process/builder/action/ActionCompilerRegistry.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jbpm.process.builder.action;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ServiceLoader;
+
+import org.jbpm.util.JbpmClassLoaderUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ActionCompilerRegistry {
+
+    private static final Logger logger = LoggerFactory.getLogger(ActionCompilerRegistry.class);
+
+    private static ActionCompilerRegistry INSTANCE;
+
+    private List<ActionCompiler> registry;
+
+    public static ActionCompilerRegistry instance() {
+        if (INSTANCE == null) {
+            INSTANCE = new ActionCompilerRegistry();
+        }
+        return INSTANCE;
+    }
+
+    protected ActionCompilerRegistry() {
+        this.registry = new ArrayList<>();
+        ServiceLoader.load(ActionCompiler.class, JbpmClassLoaderUtil.findClassLoader()).forEach(registry::add);
+    }
+
+    public void register(ActionCompiler actionCompiler) {
+        this.registry.add(actionCompiler);
+        logger.debug("Manual registration of scripting language {} with instance {}", List.of(actionCompiler.dialects()), actionCompiler);
+    }
+
+    public ActionCompiler find(String language) {
+        for (ActionCompiler transformer : registry) {
+            if (transformer.accept(language)) {
+                return transformer;
+            }
+        }
+        throw new IllegalArgumentException("action compiler not support for dialect " + language);
+    }
+}
\ No newline at end of file
diff --git a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/process/builder/action/JavaActionCompiler.java b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/process/builder/action/JavaActionCompiler.java
new file mode 100644
index 00000000000..f2762126f28
--- /dev/null
+++ b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/process/builder/action/JavaActionCompiler.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jbpm.process.builder.action;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.jbpm.compiler.canonical.AbstractNodeVisitor;
+import org.jbpm.process.core.context.variable.Variable;
+import org.jbpm.process.core.context.variable.VariableScope;
+import org.jbpm.workflow.core.impl.NodeImpl;
+
+import com.github.javaparser.StaticJavaParser;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.body.Parameter;
+import com.github.javaparser.ast.expr.AssignExpr;
+import com.github.javaparser.ast.expr.AssignExpr.Operator;
+import com.github.javaparser.ast.expr.CastExpr;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.LambdaExpr;
+import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.NameExpr;
+import com.github.javaparser.ast.expr.StringLiteralExpr;
+import com.github.javaparser.ast.expr.VariableDeclarationExpr;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.ast.type.ClassOrInterfaceType;
+import com.github.javaparser.ast.type.Type;
+
+public class JavaActionCompiler implements ActionCompiler {
+
+    @Override
+    public String[] dialects() {
+        return new String[] { "java" };
+    }
+
+    @Override
+    public boolean accept(String dialect) {
+        return dialect.toLowerCase().contains("java");
+    }
+
+    @Override
+    public Expression buildAction(NodeImpl nodeImpl, String script) {
+        BlockStmt newDroolsConsequenceActionExpression = new BlockStmt();
+        newDroolsConsequenceActionExpression = StaticJavaParser.parseBlock("{" + script + "}");
+        Set<NameExpr> identifiers = new HashSet<>(newDroolsConsequenceActionExpression.findAll(NameExpr.class));
+        for (NameExpr identifier : identifiers) {
+            VariableScope scope = (VariableScope) nodeImpl.resolveContext(VariableScope.VARIABLE_SCOPE, identifier.getNameAsString());
+            if (scope == null) {
+                continue;
+            }
+            Variable var = scope.findVariable(identifier.getNameAsString());
+            if (var == null) {
+                continue;
+            }
+            Type type = StaticJavaParser.parseType(var.getType().getStringType());
+            VariableDeclarationExpr target = new VariableDeclarationExpr(type, var.getName());
+            Expression source = new MethodCallExpr(new NameExpr(AbstractNodeVisitor.KCONTEXT_VAR), "getVariable", NodeList.nodeList(new StringLiteralExpr(var.getName())));
+            source = new CastExpr(type, source);
+            AssignExpr assign = new AssignExpr(target, source, Operator.ASSIGN);
+            newDroolsConsequenceActionExpression.addStatement(0, assign);
+        }
+        ClassOrInterfaceType type = StaticJavaParser.parseClassOrInterfaceType(org.kie.kogito.internal.process.runtime.KogitoProcessContext.class.getName());
+        return new LambdaExpr(NodeList.nodeList(new Parameter(type, AbstractNodeVisitor.KCONTEXT_VAR)), newDroolsConsequenceActionExpression, true);
+    }
+
+}
diff --git a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/process/builder/action/MVELActionCompiler.java b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/process/builder/action/MVELActionCompiler.java
new file mode 100644
index 00000000000..83124237aff
--- /dev/null
+++ b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/process/builder/action/MVELActionCompiler.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jbpm.process.builder.action;
+
+import org.jbpm.compiler.canonical.AbstractNodeVisitor;
+import org.jbpm.workflow.core.impl.NodeImpl;
+
+import com.github.javaparser.StaticJavaParser;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.body.Parameter;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.LambdaExpr;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.ast.type.ClassOrInterfaceType;
+
+import static org.kie.kogito.internal.utils.ConversionUtils.sanitizeString;
+
+public class MVELActionCompiler implements ActionCompiler {
+
+    @Override
+    public String[] dialects() {
+        return new String[] { "mvel" };
+    }
+
+    @Override
+    public Expression buildAction(NodeImpl nodeImpl, String script) {
+        BlockStmt actionExpression = StaticJavaParser.parseBlock(
+                "{ org.mvel2.MVEL.eval(\"" + sanitizeString(script) +
+                        "\", new org.jbpm.workflow.instance.impl.NodeInstanceResolverFactory((org.jbpm.workflow.instance.NodeInstance) kcontext.getNodeInstance())); }");
+        ClassOrInterfaceType type = StaticJavaParser.parseClassOrInterfaceType(org.kie.kogito.internal.process.runtime.KogitoProcessContext.class.getName());
+        return new LambdaExpr(NodeList.nodeList(new Parameter(type, AbstractNodeVisitor.KCONTEXT_VAR)), actionExpression, true);
+    }
+
+}
diff --git a/jbpm/jbpm-flow-builder/src/main/resources/META-INF/services/org.jbpm.process.builder.action.ActionCompiler b/jbpm/jbpm-flow-builder/src/main/resources/META-INF/services/org.jbpm.process.builder.action.ActionCompiler
new file mode 100644
index 00000000000..d9494beeea5
--- /dev/null
+++ b/jbpm/jbpm-flow-builder/src/main/resources/META-INF/services/org.jbpm.process.builder.action.ActionCompiler
@@ -0,0 +1,2 @@
+org.jbpm.process.builder.action.JavaActionCompiler
+org.jbpm.process.builder.action.MVELActionCompiler
\ No newline at end of file
diff --git a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/AbstractCompositeNodeFactory.java b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/AbstractCompositeNodeFactory.java
index 0befff9481e..329534bbedc 100644
--- a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/AbstractCompositeNodeFactory.java
+++ b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/AbstractCompositeNodeFactory.java
@@ -109,4 +109,5 @@ public P done() {
         }
         return super.done();
     }
+
 }
diff --git a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/ExtendedNodeFactory.java b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/ExtendedNodeFactory.java
index 0653d5f6df6..0a22a65261d 100755
--- a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/ExtendedNodeFactory.java
+++ b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/ExtendedNodeFactory.java
@@ -18,14 +18,9 @@
  */
 package org.jbpm.ruleflow.core.factory;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import org.jbpm.ruleflow.core.RuleFlowNodeContainerFactory;
-import org.jbpm.workflow.core.DroolsAction;
 import org.jbpm.workflow.core.Node;
 import org.jbpm.workflow.core.NodeContainer;
-import org.jbpm.workflow.core.impl.DroolsConsequenceAction;
 import org.jbpm.workflow.core.impl.ExtendedNodeImpl;
 import org.kie.api.definition.process.WorkflowElementIdentifier;
 
@@ -39,25 +34,4 @@ protected ExtendedNodeImpl getExtendedNode() {
         return (ExtendedNodeImpl) getNode();
     }
 
-    public T onEntryAction(String dialect, String action) {
-        if (getExtendedNode().getActions(dialect) != null) {
-            getExtendedNode().getActions(dialect).add(new DroolsConsequenceAction(dialect, action));
-        } else {
-            List<DroolsAction> actions = new ArrayList<>();
-            actions.add(new DroolsConsequenceAction(dialect, action));
-            getExtendedNode().setActions(ExtendedNodeImpl.EVENT_NODE_ENTER, actions);
-        }
-        return (T) this;
-    }
-
-    public T onExitAction(String dialect, String action) {
-        if (getExtendedNode().getActions(dialect) != null) {
-            getExtendedNode().getActions(dialect).add(new DroolsConsequenceAction(dialect, action));
-        } else {
-            List<DroolsAction> actions = new ArrayList<>();
-            actions.add(new DroolsConsequenceAction(dialect, action));
-            getExtendedNode().setActions(ExtendedNodeImpl.EVENT_NODE_EXIT, actions);
-        }
-        return (T) this;
-    }
 }
diff --git a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/NodeFactory.java b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/NodeFactory.java
index bcbfb1f475f..ba22a6d53bc 100755
--- a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/NodeFactory.java
+++ b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/NodeFactory.java
@@ -18,10 +18,15 @@
  */
 package org.jbpm.ruleflow.core.factory;
 
+import java.util.ArrayList;
+
 import org.jbpm.process.core.context.variable.Mappable;
+import org.jbpm.process.instance.impl.Action;
 import org.jbpm.ruleflow.core.RuleFlowNodeContainerFactory;
 import org.jbpm.workflow.core.Node;
 import org.jbpm.workflow.core.NodeContainer;
+import org.jbpm.workflow.core.impl.DroolsConsequenceAction;
+import org.jbpm.workflow.core.impl.ExtendedNodeImpl;
 import org.kie.api.definition.process.WorkflowElementIdentifier;
 
 public abstract class NodeFactory<T extends NodeFactory<T, P>, P extends RuleFlowNodeContainerFactory<P, ?>> implements MappableNodeFactory<T> {
@@ -71,4 +76,27 @@ public Mappable getMappableNode() {
         return (Mappable) node;
     }
 
+    public T onEntryAction(String dialect, String action) {
+        return onActionScript(ExtendedNodeImpl.EVENT_NODE_ENTER, dialect, action, null);
+    }
+
+    public T onExitAction(String dialect, String action) {
+        return onActionScript(ExtendedNodeImpl.EVENT_NODE_EXIT, dialect, action, null);
+    }
+
+    public T onActionScript(String type, String dialect, String script, Action compiledScript) {
+        DroolsConsequenceAction action = new DroolsConsequenceAction(dialect, script);
+        if (compiledScript != null) {
+            action.setMetaData("Action", compiledScript);
+        }
+        if (getExtendedNode().getActions(type) == null) {
+            getExtendedNode().setActions(type, new ArrayList<>());
+        }
+        getExtendedNode().getActions(type).add(action);
+        return (T) this;
+    }
+
+    private ExtendedNodeImpl getExtendedNode() {
+        return (ExtendedNodeImpl) getNode();
+    }
 }
diff --git a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/validation/RuleFlowProcessValidator.java b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/validation/RuleFlowProcessValidator.java
index f1bb75950a4..5319367af5d 100755
--- a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/validation/RuleFlowProcessValidator.java
+++ b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/validation/RuleFlowProcessValidator.java
@@ -45,12 +45,10 @@
 import org.jbpm.ruleflow.core.Metadata;
 import org.jbpm.ruleflow.core.RuleFlowProcess;
 import org.jbpm.workflow.core.Constraint;
-import org.jbpm.workflow.core.DroolsAction;
 import org.jbpm.workflow.core.Node;
 import org.jbpm.workflow.core.WorkflowProcess;
 import org.jbpm.workflow.core.impl.DataAssociation;
 import org.jbpm.workflow.core.impl.DroolsConsequenceAction;
-import org.jbpm.workflow.core.impl.ExtendedNodeImpl;
 import org.jbpm.workflow.core.impl.NodeImpl;
 import org.jbpm.workflow.core.node.ActionNode;
 import org.jbpm.workflow.core.node.BoundaryEventNode;
@@ -189,7 +187,6 @@ protected void validateNodes(org.kie.api.definition.process.Node[] nodes,
                         errors);
             } else if (node instanceof RuleSetNode) {
                 final RuleSetNode ruleSetNode = (RuleSetNode) node;
-                validateOnEntryOnExitScripts(ruleSetNode, errors, process);
                 if (ruleSetNode.getFrom() == null && !acceptsNoIncomingConnections(node)) {
                     addErrorMessage(process,
                             node,
@@ -318,7 +315,6 @@ protected void validateNodes(org.kie.api.definition.process.Node[] nodes,
                 }
             } else if (node instanceof MilestoneNode) {
                 final MilestoneNode milestone = (MilestoneNode) node;
-                validateOnEntryOnExitScripts(milestone, errors, process);
                 if (milestone.getFrom() == null && !acceptsNoIncomingConnections(node)) {
                     addErrorMessage(process,
                             node,
@@ -350,7 +346,6 @@ protected void validateNodes(org.kie.api.definition.process.Node[] nodes,
                 }
             } else if (node instanceof SubProcessNode) {
                 final SubProcessNode subProcess = (SubProcessNode) node;
-                validateOnEntryOnExitScripts(subProcess, errors, process);
                 if (subProcess.getFrom() == null && !acceptsNoIncomingConnections(node)) {
                     addErrorMessage(process,
                             node,
@@ -429,7 +424,6 @@ protected void validateNodes(org.kie.api.definition.process.Node[] nodes,
                 }
             } else if (node instanceof WorkItemNode) {
                 final WorkItemNode workItemNode = (WorkItemNode) node;
-                validateOnEntryOnExitScripts(workItemNode, errors, process);
                 if (workItemNode.getFrom() == null && !acceptsNoIncomingConnections(node)) {
                     addErrorMessage(process,
                             node,
@@ -469,7 +463,6 @@ protected void validateNodes(org.kie.api.definition.process.Node[] nodes,
                 }
             } else if (node instanceof ForEachNode) {
                 final ForEachNode forEachNode = (ForEachNode) node;
-                validateOnEntryOnExitScripts(forEachNode, errors, process);
                 String variableName = forEachNode.getVariableName();
                 if (variableName == null || "".equals(variableName)) {
                     addErrorMessage(process,
@@ -513,7 +506,6 @@ protected void validateNodes(org.kie.api.definition.process.Node[] nodes,
                         process);
             } else if (node instanceof DynamicNode) {
                 final DynamicNode dynamicNode = (DynamicNode) node;
-                validateOnEntryOnExitScripts(dynamicNode, errors, process);
 
                 if (dynamicNode.getDefaultIncomingConnections().isEmpty() && !acceptsNoIncomingConnections(dynamicNode)) {
                     addErrorMessage(process,
@@ -540,7 +532,6 @@ protected void validateNodes(org.kie.api.definition.process.Node[] nodes,
                         process);
             } else if (node instanceof CompositeNode) {
                 final CompositeNode compositeNode = (CompositeNode) node;
-                validateOnEntryOnExitScripts(compositeNode, errors, process);
                 for (Map.Entry<String, NodeAndType> inType : compositeNode.getLinkedIncomingNodes().entrySet()) {
                     if (compositeNode.getIncomingConnections(inType.getKey()).isEmpty() && !acceptsNoIncomingConnections(node)) {
                         addErrorMessage(process,
@@ -949,20 +940,6 @@ public ProcessValidationError[] validateProcess(Process process) {
         return validateProcess((RuleFlowProcess) process);
     }
 
-    //TODO To be removed once https://issues.redhat.com/browse/KOGITO-2067 is fixed
-    private void validateOnEntryOnExitScripts(Node node, List<ProcessValidationError> errors, RuleFlowProcess process) {
-        if (node instanceof ExtendedNodeImpl) {
-            List<DroolsAction> actions = ((ExtendedNodeImpl) node).getActions(ExtendedNodeImpl.EVENT_NODE_ENTER);
-            if (actions != null && !actions.isEmpty()) {
-                addErrorMessage(process, node, errors, "On Entry Action is not yet supported in Kogito");
-            }
-            actions = ((ExtendedNodeImpl) node).getActions(ExtendedNodeImpl.EVENT_NODE_EXIT);
-            if (actions != null && !actions.isEmpty()) {
-                addErrorMessage(process, node, errors, "On Exit Action is not yet supported in Kogito");
-            }
-        }
-    }
-
     private void validateVariables(List<ProcessValidationError> errors, RuleFlowProcess process) {
 
         List<Variable> variables = process.getVariableScope().getVariables();
diff --git a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/core/impl/ExtendedNodeImpl.java b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/core/impl/ExtendedNodeImpl.java
index 8a41d90e607..a0f4e215830 100755
--- a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/core/impl/ExtendedNodeImpl.java
+++ b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/core/impl/ExtendedNodeImpl.java
@@ -39,6 +39,10 @@ public void setActions(String type, List<DroolsAction> actions) {
         this.actions.put(type, actions);
     }
 
+    public boolean hasActions(String type) {
+        return this.actions.get(type) != null;
+    }
+
     public List<DroolsAction> getActions(String type) {
         return this.actions.get(type);
     }
diff --git a/jbpm/jbpm-flow/src/test/java/org/jbpm/ruleflow/core/validation/RuleFlowProcessValidatorTest.java b/jbpm/jbpm-flow/src/test/java/org/jbpm/ruleflow/core/validation/RuleFlowProcessValidatorTest.java
index f6e52f25e7c..a2d99b7a714 100755
--- a/jbpm/jbpm-flow/src/test/java/org/jbpm/ruleflow/core/validation/RuleFlowProcessValidatorTest.java
+++ b/jbpm/jbpm-flow/src/test/java/org/jbpm/ruleflow/core/validation/RuleFlowProcessValidatorTest.java
@@ -26,26 +26,17 @@
 import org.jbpm.process.core.validation.ProcessValidationError;
 import org.jbpm.ruleflow.core.RuleFlowProcess;
 import org.jbpm.ruleflow.core.WorkflowElementIdentifierFactory;
-import org.jbpm.workflow.core.DroolsAction;
 import org.jbpm.workflow.core.Node;
 import org.jbpm.workflow.core.impl.DroolsConsequenceAction;
-import org.jbpm.workflow.core.impl.ExtendedNodeImpl;
 import org.jbpm.workflow.core.node.ActionNode;
 import org.jbpm.workflow.core.node.CompositeNode;
 import org.jbpm.workflow.core.node.DynamicNode;
 import org.jbpm.workflow.core.node.EndNode;
-import org.jbpm.workflow.core.node.ForEachNode;
-import org.jbpm.workflow.core.node.MilestoneNode;
-import org.jbpm.workflow.core.node.RuleSetNode;
 import org.jbpm.workflow.core.node.StartNode;
-import org.jbpm.workflow.core.node.SubProcessNode;
-import org.jbpm.workflow.core.node.WorkItemNode;
-import org.jbpm.workflow.instance.rule.RuleType;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.kie.api.definition.process.WorkflowElementIdentifier;
 
-import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -211,32 +202,6 @@ void testCompositeNodeNoStart() {
         assertThat(errors[0].getMessage()).isEqualTo("Node 'CompositeNode' [3] Composite has no start node defined.");
     }
 
-    //TODO To be removed once https://issues.redhat.com/browse/KOGITO-2067 is fixed
-    @Test
-    void testOnEntryOnExitValidation() {
-        testNodeOnEntryOnExit(new MilestoneNode());
-        RuleSetNode ruleSetNode = new RuleSetNode();
-        ruleSetNode.setRuleType(mock(RuleType.class));
-        testNodeOnEntryOnExit(ruleSetNode);
-        testNodeOnEntryOnExit(new SubProcessNode());
-        testNodeOnEntryOnExit(new WorkItemNode());
-        testNodeOnEntryOnExit(new ForEachNode(one));
-        testNodeOnEntryOnExit(new DynamicNode());
-        testNodeOnEntryOnExit(new CompositeNode());
-    }
-
-    private void testNodeOnEntryOnExit(ExtendedNodeImpl node) {
-        List<ProcessValidationError> errors = new ArrayList<>();
-        node.setName("name");
-        node.setId(node.getId());
-        node.setActions(ExtendedNodeImpl.EVENT_NODE_ENTER, singletonList(new DroolsAction()));
-        node.setActions(ExtendedNodeImpl.EVENT_NODE_EXIT, singletonList(new DroolsAction()));
-        validator.validateNodes(new org.kie.api.definition.process.Node[] { node }, errors, process);
-        assertThat(errors).extracting("message").contains(
-                "Node 'name' [" + node.getId().toExternalFormat() + "] On Entry Action is not yet supported in Kogito",
-                "Node 'name' [" + node.getId().toExternalFormat() + "] On Exit Action is not yet supported in Kogito");
-    }
-
     @Test
     void testScriptTaskDialect() {
         StartNode startNode = new StartNode();
diff --git a/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/ActivityTest.java b/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/ActivityTest.java
index 9af1206fb28..319595851d3 100755
--- a/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/ActivityTest.java
+++ b/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/ActivityTest.java
@@ -34,6 +34,8 @@
 import org.jbpm.bpmn2.objects.HelloService;
 import org.jbpm.bpmn2.objects.Person;
 import org.jbpm.bpmn2.objects.TestWorkItemHandler;
+import org.jbpm.bpmn2.subprocess.SubProcessWithEntryExitScriptsModel;
+import org.jbpm.bpmn2.subprocess.SubProcessWithEntryExitScriptsProcess;
 import org.jbpm.bpmn2.test.RequirePersistence;
 import org.jbpm.process.builder.ActionBuilder;
 import org.jbpm.process.builder.AssignmentBuilder;
@@ -49,6 +51,8 @@
 import org.jbpm.process.instance.impl.demo.DoNothingWorkItemHandler;
 import org.jbpm.process.instance.impl.demo.SystemOutWorkItemHandler;
 import org.jbpm.test.util.ProcessCompletedCountDownProcessEventListener;
+import org.jbpm.test.utils.EventTrackerProcessListener;
+import org.jbpm.test.utils.ProcessTestHelper;
 import org.jbpm.workflow.core.impl.DataAssociation;
 import org.jbpm.workflow.core.impl.DataDefinition;
 import org.jbpm.workflow.core.node.ActionNode;
@@ -76,6 +80,7 @@
 import org.kie.api.event.rule.MatchCreatedEvent;
 import org.kie.api.runtime.process.DataTransformer;
 import org.kie.api.runtime.process.NodeInstance;
+import org.kie.kogito.Application;
 import org.kie.kogito.internal.process.event.DefaultKogitoProcessEventListener;
 import org.kie.kogito.internal.process.runtime.KogitoNodeInstanceContainer;
 import org.kie.kogito.internal.process.runtime.KogitoProcessInstance;
@@ -83,6 +88,7 @@
 import org.kie.kogito.internal.process.runtime.KogitoWorkItem;
 import org.kie.kogito.internal.process.runtime.KogitoWorkItemManager;
 import org.kie.kogito.internal.process.runtime.KogitoWorkflowProcessInstance;
+import org.kie.kogito.process.ProcessInstance;
 import org.kie.kogito.process.workitems.InternalKogitoWorkItem;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -426,39 +432,27 @@ public void testCallActivityWithContantsAssignment() throws Exception {
     }
 
     @Test
-    @Disabled("On Exit not supported, see https://issues.redhat.com/browse/KOGITO-2067")
     public void testSubProcessWithEntryExitScripts() throws Exception {
-        kruntime = createKogitoProcessRuntime("subprocess/BPMN2-SubProcessWithEntryExitScripts.bpmn2");
-        TestWorkItemHandler handler = new TestWorkItemHandler();
-        kruntime.getKogitoWorkItemManager().registerWorkItemHandler("Human Task", handler);
-
-        KogitoProcessInstance processInstance = kruntime.startProcess("com.sample.bpmn.hello");
-
-        assertNodeTriggered(processInstance.getStringId(), "Task1");
-        Object var1 = getProcessVarValue(processInstance, "var1");
-        assertThat(var1).isNotNull().hasToString("10");
-
-        assertNodeTriggered(processInstance.getStringId(), "Task2");
-        Object var2 = getProcessVarValue(processInstance, "var2");
-        assertThat(var2).isNotNull().hasToString("20");
-
-        assertNodeTriggered(processInstance.getStringId(), "Task3");
-        Object var3 = getProcessVarValue(processInstance, "var3");
-        assertThat(var3).isNotNull().hasToString("30");
-
-        assertNodeTriggered(processInstance.getStringId(), "SubProcess");
-        Object var4 = getProcessVarValue(processInstance, "var4");
-        assertThat(var4).isNotNull().hasToString("40");
-
-        Object var5 = getProcessVarValue(processInstance, "var5");
-        assertThat(var5).isNotNull().hasToString("50");
-
-        org.kie.kogito.internal.process.runtime.KogitoWorkItem workItem = handler.getWorkItem();
-        assertThat(workItem).isNotNull();
-
-        kruntime.getKogitoWorkItemManager().completeWorkItem(workItem.getStringId(), null);
-
-        assertProcessInstanceCompleted(processInstance);
+        Application app = ProcessTestHelper.newApplication();
+        EventTrackerProcessListener listener = new EventTrackerProcessListener();
+        ProcessTestHelper.registerProcessEventListener(app, listener);
+
+        org.kie.kogito.process.Process<SubProcessWithEntryExitScriptsModel> process = SubProcessWithEntryExitScriptsProcess.newProcess(app);
+        ProcessInstance<SubProcessWithEntryExitScriptsModel> processInstance = process.createInstance(process.createModel());
+        processInstance.start();
+
+        assertThat(listener.tracked()).anyMatch(ProcessTestHelper.triggered("Task1"));
+        assertThat(processInstance.variables().getVar1()).isNotNull().hasToString("10");
+        assertThat(listener.tracked()).anyMatch(ProcessTestHelper.triggered("Task2"));
+        assertThat(processInstance.variables().getVar2()).isNotNull().hasToString("20");
+        assertThat(listener.tracked()).anyMatch(ProcessTestHelper.triggered("Task3"));
+        assertThat(processInstance.variables().getVar3()).isNotNull().hasToString("30");
+        assertThat(listener.tracked()).anyMatch(ProcessTestHelper.triggered("SubProcess"));
+        assertThat(processInstance.variables().getVar4()).isNotNull().hasToString("40");
+        assertThat(processInstance.variables().getVar5()).isNotNull().hasToString("50");
+
+        ProcessTestHelper.completeWorkItem(processInstance, "john", Collections.emptyMap());
+        assertThat(processInstance).extracting(ProcessInstance::status).isEqualTo(ProcessInstance.STATE_COMPLETED);
     }
 
     @Test
diff --git a/jbpm/jbpm-tests/src/test/java/org/jbpm/test/utils/EventTrackerProcessListener.java b/jbpm/jbpm-tests/src/test/java/org/jbpm/test/utils/EventTrackerProcessListener.java
new file mode 100644
index 00000000000..e88492b1253
--- /dev/null
+++ b/jbpm/jbpm-tests/src/test/java/org/jbpm/test/utils/EventTrackerProcessListener.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jbpm.test.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.kie.api.event.process.ProcessNodeEvent;
+import org.kie.api.event.process.ProcessNodeLeftEvent;
+import org.kie.api.event.process.ProcessNodeTriggeredEvent;
+import org.kie.kogito.internal.process.event.DefaultKogitoProcessEventListener;
+
+public class EventTrackerProcessListener extends DefaultKogitoProcessEventListener {
+
+    List<ProcessNodeEvent> nodeEvents;
+
+    public EventTrackerProcessListener() {
+        this.nodeEvents = new ArrayList<>();
+    }
+
+    @Override
+    public void afterNodeTriggered(ProcessNodeTriggeredEvent event) {
+        nodeEvents.add(event);
+    }
+
+    @Override
+    public void afterNodeLeft(ProcessNodeLeftEvent event) {
+        nodeEvents.add(event);
+    }
+
+    public List<ProcessNodeEvent> tracked() {
+        return nodeEvents;
+    }
+}
diff --git a/jbpm/jbpm-tests/src/test/java/org/jbpm/test/utils/ProcessTestHelper.java b/jbpm/jbpm-tests/src/test/java/org/jbpm/test/utils/ProcessTestHelper.java
index d191f061931..6c1d8ac54a0 100644
--- a/jbpm/jbpm-tests/src/test/java/org/jbpm/test/utils/ProcessTestHelper.java
+++ b/jbpm/jbpm-tests/src/test/java/org/jbpm/test/utils/ProcessTestHelper.java
@@ -21,7 +21,10 @@
 import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 
+import org.kie.api.event.process.ProcessNodeEvent;
+import org.kie.api.event.process.ProcessNodeTriggeredEvent;
 import org.kie.kogito.Application;
 import org.kie.kogito.Model;
 import org.kie.kogito.StaticApplication;
@@ -76,4 +79,10 @@ public static WorkItem findWorkItem(ProcessInstance<? extends Model> processInst
         return workItems.stream().findFirst().get();
     }
 
+    public static <T extends ProcessNodeEvent> Predicate<T> triggered(String nodeName) {
+        return e -> {
+            return e instanceof ProcessNodeTriggeredEvent && nodeName.equals(((ProcessNodeTriggeredEvent) e).getNodeInstance().getNodeName());
+        };
+    }
+
 }
diff --git a/jbpm/jbpm-tools/jbpm-tools-maven-plugin/src/test/resources/unit/project/src/main/bpmn/BPMN2-SubProcessWithEntryExitScripts.bpmn2 b/jbpm/jbpm-tools/jbpm-tools-maven-plugin/src/test/resources/unit/project/src/main/bpmn/BPMN2-SubProcessWithEntryExitScripts.bpmn2
new file mode 100755
index 00000000000..3dce9dac8c6
--- /dev/null
+++ b/jbpm/jbpm-tools/jbpm-tools-maven-plugin/src/test/resources/unit/project/src/main/bpmn/BPMN2-SubProcessWithEntryExitScripts.bpmn2
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.jboss.org/drools" xmlns="http://www.jboss.org/drools" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd http://www.jboss.org/drools drools.xsd http://www.bpsim.org/schemas/1.0 bpsim.xsd" id="Definition" expressionLanguage="http://www.mvel.org/2.0" targetNamespace="http://www.jboss.org/drools" typeLanguage="http://www.java.com/javaTypes">
+  <bpmn2:itemDefinition id="_String" structureRef="String"/>
+  <bpmn2:itemDefinition id="_Integer" structureRef="Integer"/>
+  <bpmn2:process id="SubProcessWithEntryExitScripts" tns:version="1" tns:packageName="org.jbpm.bpmn2.subprocess" name="Hello World" isExecutable="true" processType="Private">
+    <bpmn2:extensionElements/>
+    <bpmn2:property id="var2" itemSubjectRef="_Integer"/>
+    <bpmn2:property id="var3" itemSubjectRef="_Integer"/>
+    <bpmn2:property id="var1" itemSubjectRef="_Integer"/>
+    <bpmn2:property id="var4" itemSubjectRef="_Integer"/>
+    <bpmn2:property id="var5" itemSubjectRef="_Integer"/>
+    <bpmn2:scriptTask id="_2" name="Task1" scriptFormat="http://www.java.com/java">
+      <bpmn2:incoming>_1-_2</bpmn2:incoming>
+      <bpmn2:outgoing>SequenceFlow_11</bpmn2:outgoing>
+      <bpmn2:script>System.err.println(&quot;Task 1, var1 = 10&quot;);
+kcontext.setVariable(&quot;var1&quot;, new Integer(10));
+</bpmn2:script>
+    </bpmn2:scriptTask>
+    <bpmn2:startEvent id="_1" name="">
+      <bpmn2:outgoing>_1-_2</bpmn2:outgoing>
+    </bpmn2:startEvent>
+    <bpmn2:sequenceFlow id="_1-_2" tns:priority="1" sourceRef="_1" targetRef="_2"/>
+    <bpmn2:scriptTask id="ScriptTask_2" name="Task3">
+      <bpmn2:incoming>SequenceFlow_12</bpmn2:incoming>
+      <bpmn2:outgoing>SequenceFlow_7</bpmn2:outgoing>
+      <bpmn2:script>System.err.println(&quot;Task 3, var3 = 30&quot;);
+kcontext.setVariable(&quot;var3&quot;,30);
+</bpmn2:script>
+    </bpmn2:scriptTask>
+    <bpmn2:sequenceFlow id="SequenceFlow_7" tns:priority="1" name="" sourceRef="ScriptTask_2" targetRef="UserTask_2"/>
+    <bpmn2:endEvent id="_3" name="">
+      <bpmn2:incoming>SequenceFlow_8</bpmn2:incoming>
+      <bpmn2:terminateEventDefinition id="TerminateEventDefinition_1"/>
+    </bpmn2:endEvent>
+    <bpmn2:userTask id="UserTask_2" name="User Task 2">
+      <bpmn2:incoming>SequenceFlow_7</bpmn2:incoming>
+      <bpmn2:outgoing>SequenceFlow_8</bpmn2:outgoing>
+      <bpmn2:ioSpecification id="_InputOutputSpecification_24">
+        <bpmn2:dataInput id="_DataInput_150" name="TaskName"/>
+        <bpmn2:dataInput id="_DataInput_151" name="Priority"/>
+        <bpmn2:dataInput id="_DataInput_152" name="Comment"/>
+        <bpmn2:dataInput id="_DataInput_153" name="GroupId"/>
+        <bpmn2:dataInput id="_DataInput_154" name="Skippable"/>
+        <bpmn2:dataInput id="_DataInput_155" name="Content"/>
+        <bpmn2:dataInput id="_DataInput_156" name="Locale"/>
+        <bpmn2:inputSet id="_InputSet_24" name="New Input Set">
+          <bpmn2:dataInputRefs>_DataInput_150</bpmn2:dataInputRefs>
+          <bpmn2:dataInputRefs>_DataInput_151</bpmn2:dataInputRefs>
+          <bpmn2:dataInputRefs>_DataInput_152</bpmn2:dataInputRefs>
+          <bpmn2:dataInputRefs>_DataInput_153</bpmn2:dataInputRefs>
+          <bpmn2:dataInputRefs>_DataInput_154</bpmn2:dataInputRefs>
+          <bpmn2:dataInputRefs>_DataInput_155</bpmn2:dataInputRefs>
+          <bpmn2:dataInputRefs>_DataInput_156</bpmn2:dataInputRefs>
+        </bpmn2:inputSet>
+        <bpmn2:outputSet id="_OutputSet_21" name="Output Set"/>
+      </bpmn2:ioSpecification>
+      <bpmn2:dataInputAssociation id="_DataInputAssociation_150">
+        <bpmn2:targetRef>_DataInput_150</bpmn2:targetRef>
+      </bpmn2:dataInputAssociation>
+      <bpmn2:dataInputAssociation id="_DataInputAssociation_151">
+        <bpmn2:targetRef>_DataInput_151</bpmn2:targetRef>
+      </bpmn2:dataInputAssociation>
+      <bpmn2:dataInputAssociation id="_DataInputAssociation_152">
+        <bpmn2:targetRef>_DataInput_152</bpmn2:targetRef>
+      </bpmn2:dataInputAssociation>
+      <bpmn2:dataInputAssociation id="_DataInputAssociation_153">
+        <bpmn2:targetRef>_DataInput_153</bpmn2:targetRef>
+      </bpmn2:dataInputAssociation>
+      <bpmn2:dataInputAssociation id="_DataInputAssociation_154">
+        <bpmn2:targetRef>_DataInput_154</bpmn2:targetRef>
+      </bpmn2:dataInputAssociation>
+      <bpmn2:dataInputAssociation id="_DataInputAssociation_155">
+        <bpmn2:targetRef>_DataInput_155</bpmn2:targetRef>
+      </bpmn2:dataInputAssociation>
+      <bpmn2:dataInputAssociation id="_DataInputAssociation_156">
+        <bpmn2:targetRef>_DataInput_156</bpmn2:targetRef>
+      </bpmn2:dataInputAssociation>
+    </bpmn2:userTask>
+    <bpmn2:sequenceFlow id="SequenceFlow_8" tns:priority="1" name="" sourceRef="UserTask_2" targetRef="_3"/>
+    <bpmn2:subProcess id="SubProcess_1" name="SubProcess">
+      <bpmn2:extensionElements>
+        <tns:onEntry-script scriptFormat="http://www.java.com/java">
+          <tns:script>System.err.println(&quot;SubProcess, var4 = 40&quot;);
+kcontext.setVariable(&quot;var4&quot;,40);
+</tns:script>
+        </tns:onEntry-script>
+        <tns:onExit-script scriptFormat="http://www.java.com/java">
+          <tns:script>System.err.println(&quot;SubProcess, var5 = 50&quot;);
+kcontext.setVariable(&quot;var5&quot;,50);
+</tns:script>
+        </tns:onExit-script>
+      </bpmn2:extensionElements>
+      <bpmn2:incoming>SequenceFlow_11</bpmn2:incoming>
+      <bpmn2:outgoing>SequenceFlow_12</bpmn2:outgoing>
+      <bpmn2:startEvent id="StartEvent_1" name="">
+        <bpmn2:outgoing>SequenceFlow_10</bpmn2:outgoing>
+      </bpmn2:startEvent>
+      <bpmn2:sequenceFlow id="SequenceFlow_10" tns:priority="1" name="" sourceRef="StartEvent_1" targetRef="ScriptTask_1"/>
+      <bpmn2:scriptTask id="ScriptTask_1" name="Task2" scriptFormat="http://www.java.com/java">
+        <bpmn2:incoming>SequenceFlow_10</bpmn2:incoming>
+        <bpmn2:outgoing>SequenceFlow_9</bpmn2:outgoing>
+        <bpmn2:script>System.err.println(&quot;Task 2, var2 = 20&quot;);
+kcontext.setVariable(&quot;var2&quot;,20);
+</bpmn2:script>
+      </bpmn2:scriptTask>
+      <bpmn2:sequenceFlow id="SequenceFlow_9" tns:priority="1" sourceRef="ScriptTask_1" targetRef="EndEvent_1"/>
+      <bpmn2:endEvent id="EndEvent_1" name="">
+        <bpmn2:incoming>SequenceFlow_9</bpmn2:incoming>
+      </bpmn2:endEvent>
+    </bpmn2:subProcess>
+    <bpmn2:sequenceFlow id="SequenceFlow_11" tns:priority="1" name="" sourceRef="_2" targetRef="SubProcess_1"/>
+    <bpmn2:sequenceFlow id="SequenceFlow_12" tns:priority="1" name="" sourceRef="SubProcess_1" targetRef="ScriptTask_2"/>
+  </bpmn2:process>
+  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
+    <bpmndi:BPMNPlane id="BPMNPlane_Process_1" bpmnElement="com.sample.bpmn.hello">
+      <bpmndi:BPMNShape id="BPMNShape_SubProcess_1" bpmnElement="SubProcess_1" isExpanded="true">
+        <dc:Bounds height="111.0" width="274.0" x="290.0" y="6.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="BPMNShape_StartEvent_1" bpmnElement="_1">
+        <dc:Bounds height="36.0" width="36.0" x="40.0" y="43.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="BPMNShape_EndEvent_1" bpmnElement="_3">
+        <dc:Bounds height="36.0" width="36.0" x="990.0" y="43.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="BPMNShape_ScriptTask_1" bpmnElement="_2">
+        <dc:Bounds height="48.0" width="80.0" x="120.0" y="39.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="BPMNShape_ScriptTask_3" bpmnElement="ScriptTask_2">
+        <dc:Bounds height="50.0" width="110.0" x="630.0" y="35.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="BPMNShape_UserTask_2" bpmnElement="UserTask_2">
+        <dc:Bounds height="50.0" width="110.0" x="820.0" y="35.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="BPMNShape_EndEvent_2" bpmnElement="EndEvent_1">
+        <dc:Bounds height="36.0" width="36.0" x="508.0" y="44.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
+        <dc:Bounds height="36.0" width="36.0" x="310.0" y="44.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="BPMNShape_ScriptTask_2" bpmnElement="ScriptTask_1">
+        <dc:Bounds height="50.0" width="110.0" x="373.0" y="37.0"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_1" bpmnElement="_1-_2">
+        <di:waypoint xsi:type="dc:Point" x="76.0" y="61.0"/>
+        <di:waypoint xsi:type="dc:Point" x="120.0" y="63.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_8" bpmnElement="SequenceFlow_7" sourceElement="BPMNShape_ScriptTask_3" targetElement="BPMNShape_UserTask_2">
+        <di:waypoint xsi:type="dc:Point" x="740.0" y="60.0"/>
+        <di:waypoint xsi:type="dc:Point" x="820.0" y="60.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_9" bpmnElement="SequenceFlow_8" sourceElement="BPMNShape_UserTask_2" targetElement="BPMNShape_EndEvent_1">
+        <di:waypoint xsi:type="dc:Point" x="930.0" y="60.0"/>
+        <di:waypoint xsi:type="dc:Point" x="990.0" y="61.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_10" bpmnElement="SequenceFlow_9" sourceElement="BPMNShape_ScriptTask_2" targetElement="BPMNShape_EndEvent_2">
+        <di:waypoint xsi:type="dc:Point" x="483.0" y="62.0"/>
+        <di:waypoint xsi:type="dc:Point" x="494.0" y="62.0"/>
+        <di:waypoint xsi:type="dc:Point" x="494.0" y="62.0"/>
+        <di:waypoint xsi:type="dc:Point" x="508.0" y="62.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_11" bpmnElement="SequenceFlow_10" sourceElement="BPMNShape_StartEvent_2" targetElement="BPMNShape_ScriptTask_2">
+        <di:waypoint xsi:type="dc:Point" x="346.0" y="62.0"/>
+        <di:waypoint xsi:type="dc:Point" x="358.0" y="62.0"/>
+        <di:waypoint xsi:type="dc:Point" x="358.0" y="62.0"/>
+        <di:waypoint xsi:type="dc:Point" x="373.0" y="62.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_12" bpmnElement="SequenceFlow_11" sourceElement="BPMNShape_ScriptTask_1" targetElement="BPMNShape_SubProcess_1">
+        <di:waypoint xsi:type="dc:Point" x="200.0" y="63.0"/>
+        <di:waypoint xsi:type="dc:Point" x="290.0" y="61.0"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_13" bpmnElement="SequenceFlow_12" sourceElement="BPMNShape_SubProcess_1" targetElement="BPMNShape_ScriptTask_3">
+        <di:waypoint xsi:type="dc:Point" x="564.0" y="61.0"/>
+        <di:waypoint xsi:type="dc:Point" x="630.0" y="60.0"/>
+      </bpmndi:BPMNEdge>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+</bpmn2:definitions>
\ No newline at end of file