> update(String id, PostResource resource) {
+ final PostData data = new PostData(resource.getTitle(), resource.getBody());
+ return repository.update(Long.parseLong(id), data).thenApplyAsync(optionalData -> {
+ return optionalData.map(op -> new PostResource(op, link(op)));
+ }, ec.current());
+ }
+
+ private String link(PostData data) {
+ // Make a point of using request context here, even if it's a bit strange
+ final Http.Request request = Http.Context.current().request();
+ final String[] hostPort = request.host().split(":");
+ String host = hostPort[0];
+ int port = (hostPort.length == 2) ? Integer.parseInt(hostPort[1]) : -1;
+ final String scheme = request.secure() ? "https" : "http";
+ try {
+ return UrlBuilder.forHost(scheme, host, port)
+ .pathSegments("v1", "posts", data.id.toString())
+ .toUrlString();
+ } catch (CharacterCodingException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+}
diff --git a/play-java-rest-api-example/app/views/index.scala.html b/play-java-rest-api-example/app/views/index.scala.html
new file mode 100644
index 000000000..b6c289527
--- /dev/null
+++ b/play-java-rest-api-example/app/views/index.scala.html
@@ -0,0 +1,39 @@
+@()
+
+
+
+
+
+ Play REST API
+
+
+
+ Play REST API
+
+
+ This is a placeholder page to show you the REST API. Use httpie to post JSON to the application.
+
+
+
+ To see all posts, you can do a GET:
+
+
+
+
+ http GET localhost:9000/v1/posts
+
+
+
+ To create new posts, do a post
+
+
+
+ http POST localhost:9000/v1/posts title="Some title" body="Some Body"
+
+
+
+ You can always look at the API directly: /v1/posts
+
+
+
+
diff --git a/play-java-rest-api-example/app/views/timeout.scala.html b/play-java-rest-api-example/app/views/timeout.scala.html
new file mode 100644
index 000000000..50a3898c8
--- /dev/null
+++ b/play-java-rest-api-example/app/views/timeout.scala.html
@@ -0,0 +1,13 @@
+@()
+
+
+
+
+ Timeout Page
+
+
+ Timeout Page
+
+ Database timed out, so showing this page instead.
+
+
diff --git a/play-java-rest-api-example/build.gradle b/play-java-rest-api-example/build.gradle
new file mode 100644
index 000000000..56079f0b1
--- /dev/null
+++ b/play-java-rest-api-example/build.gradle
@@ -0,0 +1,70 @@
+plugins {
+ id 'play'
+ id 'idea'
+ id "com.github.lkishalmi.gatling" version "0.7.1"
+}
+
+def playVersion = "2.6.21"
+def scalaVersion = System.getProperty("scala.binary.version", /* default = */ "2.12")
+def gatlingVersion = getGlatlingVersion(scalaVersion)
+
+// Gatling 2.3.0 works for Scala 2.12
+// Gatling 2.2.5 works for Scala 2.11
+String getGlatlingVersion(String scalaVer) {
+ if (scalaVer == "2.12") "2.3.0" else "2.2.5"
+}
+
+model {
+ components {
+ play {
+ platform play: playVersion, scala: scalaVersion, java: '1.8'
+ injectedRoutesGenerator = true
+
+ sources {
+ twirlTemplates {
+ defaultImports = TwirlImports.JAVA
+ }
+ }
+ }
+ }
+}
+
+project.sourceSets {
+ gatling {
+ scala.srcDirs = ["gatling"]
+ }
+}
+
+gatling {
+ sourceRoot = "gatling"
+ simulationsDir = "gatling"
+ toolVersion = gatlingVersion
+}
+
+dependencies {
+ play "com.typesafe.play:play-guice_$scalaVersion:$playVersion"
+ play "com.typesafe.play:play-logback_$scalaVersion:$playVersion"
+ play "com.typesafe.play:play-java-jpa_$scalaVersion:$playVersion"
+ play "com.h2database:h2:1.4.197"
+
+ play "org.hibernate:hibernate-core:5.2.9.Final"
+ play "io.dropwizard.metrics:metrics-core:3.2.1"
+ play "com.palominolabs.http:url-builder:1.1.0"
+ play "net.jodah:failsafe:1.0.3"
+
+ playTest "io.gatling.highcharts:gatling-charts-highcharts:$gatlingVersion"
+ playTest "io.gatling:gatling-test-framework:$gatlingVersion"
+}
+
+repositories {
+ jcenter()
+ maven {
+ name "lightbend-maven-releases"
+ url "https://repo.lightbend.com/lightbend/maven-release"
+ }
+ ivy {
+ name "lightbend-ivy-release"
+ url "https://repo.lightbend.com/lightbend/ivy-releases"
+ layout "ivy"
+ }
+}
diff --git a/play-java-rest-api-example/build.sbt b/play-java-rest-api-example/build.sbt
new file mode 100644
index 000000000..a309f141c
--- /dev/null
+++ b/play-java-rest-api-example/build.sbt
@@ -0,0 +1,45 @@
+name := """play-java-rest-api-example"""
+
+version := "2.6.x"
+
+def gatlingVersion(scalaBinVer: String): String = scalaBinVer match {
+ case "2.11" => "2.2.5"
+ case "2.12" => "2.3.1"
+}
+
+inThisBuild(
+ List(
+ crossScalaVersions := Seq("2.11.12", "2.12.8"),
+ dependencyOverrides := Seq(
+ "org.codehaus.plexus" % "plexus-utils" % "3.0.18",
+ "com.google.code.findbugs" % "jsr305" % "3.0.1",
+ "com.google.guava" % "guava" % "22.0"
+ ),
+scalaVersion := "2.12.8"
+ )
+)
+
+
+lazy val GatlingTest = config("gatling") extend Test
+
+lazy val root = (project in file(".")).enablePlugins(PlayJava, GatlingPlugin).configs(GatlingTest)
+ .settings(inConfig(GatlingTest)(Defaults.testSettings): _*)
+ .settings(
+ scalaSource in GatlingTest := baseDirectory.value / "/gatling/simulation"
+ )
+
+libraryDependencies += guice
+libraryDependencies += javaJpa
+libraryDependencies += "com.h2database" % "h2" % "1.4.197"
+
+libraryDependencies += "org.hibernate" % "hibernate-core" % "5.2.17.Final"
+libraryDependencies += "io.dropwizard.metrics" % "metrics-core" % "3.2.1"
+libraryDependencies += "com.palominolabs.http" % "url-builder" % "1.1.0"
+libraryDependencies += "net.jodah" % "failsafe" % "1.0.3"
+
+libraryDependencies += "io.gatling.highcharts" % "gatling-charts-highcharts" % gatlingVersion(scalaBinaryVersion.value) % Test
+libraryDependencies += "io.gatling" % "gatling-test-framework" % gatlingVersion(scalaBinaryVersion.value) % Test
+
+PlayKeys.externalizeResources := false
+
+testOptions in Test := Seq(Tests.Argument(TestFrameworks.JUnit, "-a", "-v"))
diff --git a/play-java-rest-api-example/conf/META-INF/persistence.xml b/play-java-rest-api-example/conf/META-INF/persistence.xml
new file mode 100644
index 000000000..7b14af7ec
--- /dev/null
+++ b/play-java-rest-api-example/conf/META-INF/persistence.xml
@@ -0,0 +1,15 @@
+
+
+
+ org.hibernate.jpa.HibernatePersistenceProvider
+ DefaultDS
+
+
+
+
+
+
+
diff --git a/play-java-rest-api-example/conf/application.conf b/play-java-rest-api-example/conf/application.conf
new file mode 100644
index 000000000..2c1026c69
--- /dev/null
+++ b/play-java-rest-api-example/conf/application.conf
@@ -0,0 +1,34 @@
+# This is the main configuration file for the application.
+# https://www.playframework.com/documentation/latest/ConfigFile
+
+
+# Point JPA at our database configuration
+jpa.default=defaultPersistenceUnit
+
+# Number of database connections
+# See https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
+fixedConnectionPool = 9
+
+db.default {
+ driver = org.h2.Driver
+ url = "jdbc:h2:mem:play"
+
+ # Provided for JPA access
+ jndiName=DefaultDS
+
+ # Set Hikari to fixed size
+ hikaricp.minimumIdle = ${fixedConnectionPool}
+ hikaricp.maximumPoolSize = ${fixedConnectionPool}
+}
+
+# disable the built in filters
+play.http.filters = play.api.http.NoHttpFilters
+
+# Job queue sized to HikariCP connection pool
+post.repository {
+ executor = "thread-pool-executor"
+ throughput = 1
+ thread-pool-executor {
+ fixed-pool-size = ${fixedConnectionPool}
+ }
+}
diff --git a/play-java-rest-api-example/conf/logback.xml b/play-java-rest-api-example/conf/logback.xml
new file mode 100644
index 000000000..19e0e19ef
--- /dev/null
+++ b/play-java-rest-api-example/conf/logback.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+ ${application.home:-.}/logs/application.log
+
+ %date [%level] from %logger in %thread - %message%n%xException
+
+
+
+
+
+ %coloredLevel %logger{15} - %message%n%xException{10}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/play-java-rest-api-example/conf/posts.routes b/play-java-rest-api-example/conf/posts.routes
new file mode 100644
index 000000000..48e55b4b0
--- /dev/null
+++ b/play-java-rest-api-example/conf/posts.routes
@@ -0,0 +1,6 @@
+
+GET / v1.post.PostController.list
+POST / v1.post.PostController.create
+
+GET /:id v1.post.PostController.show(id)
+PUT /:id v1.post.PostController.update(id)
diff --git a/play-java-rest-api-example/conf/routes b/play-java-rest-api-example/conf/routes
new file mode 100644
index 000000000..3b829b608
--- /dev/null
+++ b/play-java-rest-api-example/conf/routes
@@ -0,0 +1,3 @@
+GET / controllers.HomeController.index
+
+-> /v1/posts posts.Routes
diff --git a/play-java-rest-api-example/gatling/simulation/GatlingSpec.scala b/play-java-rest-api-example/gatling/simulation/GatlingSpec.scala
new file mode 100644
index 000000000..5252fdeff
--- /dev/null
+++ b/play-java-rest-api-example/gatling/simulation/GatlingSpec.scala
@@ -0,0 +1,39 @@
+package simulation
+
+import io.gatling.core.Predef._
+import io.gatling.http.Predef._
+import scala.concurrent.duration._
+import scala.language.postfixOps
+
+// run with "sbt gatling:test" on another machine so you don't have resources contending.
+// http://gatling.io/docs/2.2.2/general/simulation_structure.html#simulation-structure
+class GatlingSpec extends Simulation {
+
+ // change this to another machine, make sure you have Play running in producion mode
+ // i.e. sbt stage / sbt dist and running the script
+ val httpConf = http.baseURL("http://localhost:9000")
+
+ val readClients = scenario("Clients").exec(Index.refreshManyTimes)
+
+ setUp(
+ // For reference, this hits 25% CPU on a 5820K with 32 GB, running both server and load test.
+ // In general, you want to ramp up load slowly, and measure with a JVM that has been "warmed up":
+ // https://groups.google.com/forum/#!topic/gatling/mD15aj-fyo4
+ readClients.inject(rampUsers(2000) over (100 seconds)).protocols(httpConf)
+ )
+}
+
+object Index {
+
+ def post = {
+ val body = StringBody("""{ "title": "hello", "body": "world" }""")
+ exec(http("Index").post("/v1/posts").body(body).asJSON.check(status.is(200))).pause(1)
+ }
+
+ def refreshAfterOneSecond =
+ exec(http("Index").get("/").check(status.is(200))).pause(1)
+
+ val refreshManyTimes = repeat(500) {
+ refreshAfterOneSecond
+ }
+}
diff --git a/play-java-rest-api-example/gradle/wrapper/gradle-wrapper.jar b/play-java-rest-api-example/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..01b8bf6b1
Binary files /dev/null and b/play-java-rest-api-example/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/play-java-rest-api-example/gradle/wrapper/gradle-wrapper.properties b/play-java-rest-api-example/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..89dba2d9d
--- /dev/null
+++ b/play-java-rest-api-example/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/play-java-rest-api-example/gradlew b/play-java-rest-api-example/gradlew
new file mode 100755
index 000000000..cccdd3d51
--- /dev/null
+++ b/play-java-rest-api-example/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/play-java-rest-api-example/gradlew.bat b/play-java-rest-api-example/gradlew.bat
new file mode 100644
index 000000000..e95643d6a
--- /dev/null
+++ b/play-java-rest-api-example/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/play-java-rest-api-example/project/build.properties b/play-java-rest-api-example/project/build.properties
new file mode 100644
index 000000000..c0bab0494
--- /dev/null
+++ b/play-java-rest-api-example/project/build.properties
@@ -0,0 +1 @@
+sbt.version=1.2.8
diff --git a/play-java-rest-api-example/project/plugins.sbt b/play-java-rest-api-example/project/plugins.sbt
new file mode 100644
index 000000000..26ca64bc6
--- /dev/null
+++ b/play-java-rest-api-example/project/plugins.sbt
@@ -0,0 +1,6 @@
+// The Play plugin
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.21")
+
+// Load testing tool:
+// http://gatling.io/docs/2.2.2/extensions/sbt_plugin.html
+addSbtPlugin("io.gatling" % "gatling-sbt" % "2.2.2")
diff --git a/play-java-rest-api-example/public/images/favicon.png b/play-java-rest-api-example/public/images/favicon.png
new file mode 100644
index 000000000..c7d92d2ae
Binary files /dev/null and b/play-java-rest-api-example/public/images/favicon.png differ
diff --git a/play-java-rest-api-example/public/javascripts/main.js b/play-java-rest-api-example/public/javascripts/main.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/play-java-rest-api-example/public/stylesheets/main.css b/play-java-rest-api-example/public/stylesheets/main.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/play-java-rest-api-example/scripts/script-helper b/play-java-rest-api-example/scripts/script-helper
new file mode 100644
index 000000000..9a2faa643
--- /dev/null
+++ b/play-java-rest-api-example/scripts/script-helper
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+java_version=$(java -version 2>&1 | java -version 2>&1 | awk -F '"' '/version/ {print $2}')
+
+if [[ $java_version = 1.8* ]] ; then
+ echo "The build is using Java 8 ($java_version). No addional JVM params needed."
+else
+ echo "The build is using Java 9+ ($java_version). We need additional JVM parameters"
+ export _JAVA_OPTIONS="$_JAVA_OPTIONS --add-modules=java.xml.bind"
+fi
diff --git a/play-java-rest-api-example/scripts/test-gradle b/play-java-rest-api-example/scripts/test-gradle
new file mode 100755
index 000000000..84a051a20
--- /dev/null
+++ b/play-java-rest-api-example/scripts/test-gradle
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+. "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/script-helper"
+
+# Using cut because TRAVIS_SCALA_VERSION is the full Scala
+# version (for example 2.12.4), but Gradle expects just the
+# binary version (for example 2.12)
+scala_binary_version=$(echo $TRAVIS_SCALA_VERSION | cut -c1-4)
+
+echo "+------------------------------+"
+echo "| Executing tests using Gradle |"
+echo "+------------------------------+"
+./gradlew -Dscala.binary.version=$scala_binary_version check -i --stacktrace
diff --git a/play-java-rest-api-example/scripts/test-sbt b/play-java-rest-api-example/scripts/test-sbt
new file mode 100755
index 000000000..0425367b1
--- /dev/null
+++ b/play-java-rest-api-example/scripts/test-sbt
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+. "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/script-helper"
+
+echo "+----------------------------+"
+echo "| Executing tests using sbt |"
+echo "+----------------------------+"
+sbt ++$TRAVIS_SCALA_VERSION test
diff --git a/play-java-rest-api-example/test/it/IntegrationTest.java b/play-java-rest-api-example/test/it/IntegrationTest.java
new file mode 100644
index 000000000..1325f43f6
--- /dev/null
+++ b/play-java-rest-api-example/test/it/IntegrationTest.java
@@ -0,0 +1,71 @@
+package it;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.junit.Test;
+import play.Application;
+import play.inject.guice.GuiceApplicationBuilder;
+import play.libs.Json;
+import play.mvc.Http;
+import play.mvc.Result;
+import play.test.WithApplication;
+import v1.post.PostData;
+import v1.post.PostRepository;
+import v1.post.PostResource;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+import static play.test.Helpers.*;
+
+public class IntegrationTest extends WithApplication {
+
+ @Override
+ protected Application provideApplication() {
+ return new GuiceApplicationBuilder().build();
+ }
+
+ @Test
+ public void testList() {
+ PostRepository repository = app.injector().instanceOf(PostRepository.class);
+ repository.create(new PostData("title", "body"));
+
+ Http.RequestBuilder request = new Http.RequestBuilder()
+ .method(GET)
+ .uri("/v1/posts");
+
+ Result result = route(app, request);
+ final String body = contentAsString(result);
+ assertThat(body, containsString("body"));
+ }
+
+ @Test
+ public void testTimeoutOnUpdate() {
+ PostRepository repository = app.injector().instanceOf(PostRepository.class);
+ repository.create(new PostData("title", "body"));
+
+ JsonNode json = Json.toJson(new PostResource("1", "http://localhost:9000/v1/posts/1", "some title", "somebody"));
+
+ Http.RequestBuilder request = new Http.RequestBuilder()
+ .method(PUT)
+ .bodyJson(json)
+ .uri("/v1/posts/1");
+
+ Result result = route(app, request);
+ assertThat(result.status(), equalTo(GATEWAY_TIMEOUT));
+ }
+
+ @Test
+ public void testCircuitBreakerOnShow() {
+ PostRepository repository = app.injector().instanceOf(PostRepository.class);
+ repository.create(new PostData("title", "body"));
+
+ Http.RequestBuilder request = new Http.RequestBuilder()
+ .method(GET)
+ .uri("/v1/posts/1");
+
+ Result result = route(app, request);
+ assertThat(result.status(), equalTo(SERVICE_UNAVAILABLE));
+ }
+
+
+}