diff --git a/karate-gatling/pom.xml b/karate-gatling/pom.xml
index e28c28d0a..5be3d95e4 100644
--- a/karate-gatling/pom.xml
+++ b/karate-gatling/pom.xml
@@ -32,48 +32,83 @@
scala-library
2.13.9
+
+ org.junit.jupiter
+ junit-jupiter-api
+ ${junit5.version}
+
+
+
- src/main/scala
-
-
+
+
src/test/resources
- src/test/scala
+ src/test/java
**/*.java
- **/*.scala
-
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ default-compile
+
+ none
+
+
+ default-testCompile
+
+ none
+
+
+
+
net.alchim31.maven
scala-maven-plugin
4.8.1
+
+
+ -Jbackend:GenBCode
+ -Jdelambdafy:method
+ -release:11
+ -deprecation
+ -feature
+ -unchecked
+ -language:implicitConversions
+ -language:postfixOps
+
+
-
- compile
- testCompile
-
-
-
- -Jbackend:GenBCode
- -Jdelambdafy:method
- -release:11
- -deprecation
- -feature
- -unchecked
- -language:implicitConversions
- -language:postfixOps
-
-
+ scala-compile
+ compile
+
+ add-source
+ compile
+
+
+ scala-test-compile
+ test-compile
+
+ add-source
+ testCompile
+
+
+
io.gatling
diff --git a/karate-gatling/src/main/java/com/intuit/karate/gatling/javaapi/KarateDsl.java b/karate-gatling/src/main/java/com/intuit/karate/gatling/javaapi/KarateDsl.java
new file mode 100644
index 000000000..20f211806
--- /dev/null
+++ b/karate-gatling/src/main/java/com/intuit/karate/gatling/javaapi/KarateDsl.java
@@ -0,0 +1,51 @@
+package com.intuit.karate.gatling.javaapi;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import io.gatling.javaapi.core.*;
+import io.gatling.javaapi.core.internal.Converters;
+import io.gatling.javaapi.http.*;
+import scala.collection.mutable.ArrayBuffer;
+import scala.collection.mutable.Buffer;
+import scala.collection.immutable.Seq;
+
+import com.intuit.karate.gatling.PreDef;
+import com.intuit.karate.gatling.javaapi.KarateUriPattern;
+import com.intuit.karate.gatling.javaapi.KarateUriPattern.KarateUriPatternBuilder;
+import com.intuit.karate.gatling.MethodPause;
+
+import static io.gatling.javaapi.core.CoreDsl.*;
+import static io.gatling.javaapi.http.HttpDsl.*;
+
+public class KarateDsl {
+
+ public static KarateUriPatternBuilder uri(String uri) {
+ return new KarateUriPatternBuilder(uri);
+ }
+
+ public static KarateProtocolBuilder karateProtocol(KarateUriPattern... patterns) {
+ return new KarateProtocolBuilder(Arrays.stream(patterns).collect(Collectors.toMap(KarateUriPattern::getUri, pattern -> Converters.toScalaSeq(pattern.getPauses()))));
+ }
+
+ public static ActionBuilder karateFeature(String name, String... tags) {
+ return () -> PreDef.karateFeature(name, Converters.toScalaSeq(tags));
+ }
+
+
+ public static ActionBuilder karateSet(String key, final Function supplier) {
+ return () -> PreDef.karateSet(key, session -> supplier.apply(new Session(session)));
+ }
+
+ public static MethodPause method(String method, int durationInMillis) {
+ return new MethodPause(method, durationInMillis);
+ }
+
+}
diff --git a/karate-gatling/src/main/java/com/intuit/karate/gatling/javaapi/KarateProtocolBuilder.java b/karate-gatling/src/main/java/com/intuit/karate/gatling/javaapi/KarateProtocolBuilder.java
new file mode 100644
index 000000000..8ee4b3d03
--- /dev/null
+++ b/karate-gatling/src/main/java/com/intuit/karate/gatling/javaapi/KarateProtocolBuilder.java
@@ -0,0 +1,42 @@
+package com.intuit.karate.gatling.javaapi;
+
+
+import java.util.Collections;
+import java.util.function.BiFunction;
+
+import com.intuit.karate.Runner;
+import com.intuit.karate.core.ScenarioRuntime;
+import com.intuit.karate.gatling.KarateProtocol;
+import com.intuit.karate.gatling.MethodPause;
+import com.intuit.karate.http.HttpRequest;
+
+import io.gatling.core.protocol.Protocol;
+import io.gatling.javaapi.core.ProtocolBuilder;
+import io.gatling.javaapi.core.internal.Converters;
+import scala.collection.immutable.Seq;
+import scala.collection.immutable.Map;
+
+public class KarateProtocolBuilder implements ProtocolBuilder {
+
+ public BiFunction nameResolver;
+ public Runner.Builder runner = new Runner.Builder();
+
+ private final Map> uriPatterns;
+
+ // Takes a JAVA Map (easier for testing) containaing SCALA MethodPauses (easier to read, save an extra Java MethodPause class and another conversion)
+ public KarateProtocolBuilder(java.util.Map> uriPatterns) {
+ this.uriPatterns = Converters.toScalaMap(uriPatterns);
+ }
+
+ @Override
+ public KarateProtocol protocol() {
+ KarateProtocol protocol = new KarateProtocol(uriPatterns);
+ if (nameResolver != null) {
+ protocol.nameResolver_$eq((req, sr) -> nameResolver.apply(req, sr));
+ }
+ protocol.runner_$eq(runner);
+ return protocol;
+ }
+
+
+}
diff --git a/karate-gatling/src/main/java/com/intuit/karate/gatling/javaapi/KarateUriPattern.java b/karate-gatling/src/main/java/com/intuit/karate/gatling/javaapi/KarateUriPattern.java
new file mode 100644
index 000000000..40ebae3db
--- /dev/null
+++ b/karate-gatling/src/main/java/com/intuit/karate/gatling/javaapi/KarateUriPattern.java
@@ -0,0 +1,58 @@
+package com.intuit.karate.gatling.javaapi;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import com.intuit.karate.gatling.MethodPause;
+
+/** CLass to be used as a parameter of KarateDsl.karateProtocol.
+ *
+ * Instances are obtained from KarateDsl.uri() chained with nil() or pauseFor() and won't typically be created directly.
+ */
+public class KarateUriPattern {
+ final String uri;
+ final List pauses;
+
+ KarateUriPattern(String uri, List pauses) {
+ this.uri = uri;
+ this.pauses = pauses;
+ }
+
+ String getUri() {
+ return uri;
+ }
+
+ List getPauses() {
+ return pauses;
+ }
+
+ public static class KarateUriPatternBuilder {
+ private final String uri;
+
+ KarateUriPatternBuilder(String uri) {
+ this.uri = uri;
+ }
+
+ /**
+ * Creates a uriPattern with no pauses
+ * @return
+ */
+ public KarateUriPattern nil() {
+ return new KarateUriPattern(uri, Collections.emptyList());
+ }
+
+ public KarateUriPattern pauseFor(String method, int durationInMillis) {
+ return pauseFor(KarateDsl.method(method, durationInMillis));
+ }
+
+ public KarateUriPattern pauseFor(String method1, int durationInMillis1, String method2, int durationInMillis2) {
+ return pauseFor(KarateDsl.method(method1, durationInMillis1), KarateDsl.method(method2, durationInMillis2));
+ }
+
+ public KarateUriPattern pauseFor(MethodPause... pauses) {
+ return new KarateUriPattern(uri, Arrays.asList(pauses));
+ }
+ }
+}
+
diff --git a/karate-gatling/src/main/scala/com/intuit/karate/gatling/Dummy.java b/karate-gatling/src/main/scala/com/intuit/karate/gatling/Dummy.java
deleted file mode 100644
index c46cf1d20..000000000
--- a/karate-gatling/src/main/scala/com/intuit/karate/gatling/Dummy.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.intuit.karate.gatling;
-
-public class Dummy {
- // just to keep the javadoc rule in maven central happy
-}
diff --git a/karate-gatling/src/test/java/com/intuit/karate/gatling/javaapi/KarateProtocolBuilderTest.java b/karate-gatling/src/test/java/com/intuit/karate/gatling/javaapi/KarateProtocolBuilderTest.java
new file mode 100644
index 000000000..49303f828
--- /dev/null
+++ b/karate-gatling/src/test/java/com/intuit/karate/gatling/javaapi/KarateProtocolBuilderTest.java
@@ -0,0 +1,66 @@
+package com.intuit.karate.gatling.javaapi;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.function.BiFunction;
+
+import org.junit.jupiter.api.Test;
+
+import com.intuit.karate.Runner;
+import com.intuit.karate.core.ScenarioRuntime;
+import com.intuit.karate.http.HttpRequest;
+
+import io.gatling.javaapi.core.internal.Converters;
+
+import com.intuit.karate.gatling.KarateProtocol;
+import com.intuit.karate.gatling.MethodPause;
+
+
+class KarateProtocolBuilderTest {
+
+ // Validates that the supplied nameResolver, runner and uriPatterns are taken into account.
+ @Test
+ void karateProtocol() throws Exception {
+ KarateProtocolBuilder protocolBuilder = new KarateProtocolBuilder(Collections.singletonMap("foo", Converters.toScalaSeq(Collections.singletonList(new MethodPause("get", 110)))));
+
+ protocolBuilder.nameResolver = (req, sr) -> "test name resolver";
+
+ protocolBuilder.runner.karateEnv("test");
+
+ KarateProtocol protocol = protocolBuilder.protocol();
+
+ assertEquals("test name resolver", protocol.nameResolver().apply(null, null));
+
+ Field envField = Runner.Builder.class.getDeclaredField("env");
+ envField.setAccessible(true);
+ String env = (String)envField.get(protocol.runner());
+
+ assertEquals("test", env);
+
+ assertEquals(110, protocol.pauseFor("foo", "get"));
+ }
+
+ @Test
+ void uriPatterns() {
+
+ KarateProtocol protocol = KarateDsl.karateProtocol(
+ KarateDsl.uri("foo").nil(),
+ KarateDsl.uri("bar").pauseFor("get", 110, "post", 220)
+ ).protocol();
+
+ assertEquals(110, protocol.pauseFor("bar", "get"));
+ assertEquals(220, protocol.pauseFor("bar", "post"));
+ assertEquals(0, protocol.pauseFor("bar", "put"));
+ assertEquals(0, protocol.pauseFor("foo", "get"));
+ assertEquals(0, protocol.pauseFor("foobar", "get"));
+
+ assertTrue(protocol.pathMatches("/foo").isDefined());
+ assertTrue(protocol.pathMatches("/bar").isDefined());
+ assertFalse(protocol.pathMatches("/foobar").isDefined());
+
+ }
+}
diff --git a/karate-gatling/src/test/java/mock/CatsChainedSimulation.java b/karate-gatling/src/test/java/mock/CatsChainedSimulation.java
new file mode 100644
index 000000000..6149b4e81
--- /dev/null
+++ b/karate-gatling/src/test/java/mock/CatsChainedSimulation.java
@@ -0,0 +1,45 @@
+package mock;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Random;
+import java.util.stream.Stream;
+import static com.intuit.karate.gatling.javaapi.KarateDsl.*;
+import static io.gatling.javaapi.core.CoreDsl.details;
+import static io.gatling.javaapi.core.CoreDsl.feed;
+import static io.gatling.javaapi.core.CoreDsl.rampUsers;
+import static io.gatling.javaapi.core.CoreDsl.scenario;
+
+import io.gatling.javaapi.core.*;
+
+public class CatsChainedSimulation extends Simulation {
+
+ public CatsChainedSimulation() {
+ MockUtils.startServer(0);
+
+ ProtocolBuilder protocol = karateProtocol(uri("/cats/{id}").nil());
+
+ Iterator