Browse Source

Update Play2 Scala (#2986)

* http benchmark should not depend on a database

* update deps

* update jdbc args (in mysql 5.7+ ssl is required, need to explicitly disable)

* performance config

* fix dependency version

* fix deprecation warnings

* add guice dependency

* add guice dependency

* disable filters

* set default header; workaround charset warnings

* add guice dependency

* add default response header to text/plain

* impossible to use Guice with Play 2.6 ReactiveMongo; switch to MacWire

* fix deprecated keys

* jdbc profile needs trailing '$' in class name
N.S. Cutler 7 years ago
parent
commit
dfe0b4e789
30 changed files with 157 additions and 199 deletions
  1. 0 23
      frameworks/Scala/play2-scala/play2-scala-anorm/app/Filters.scala
  2. 12 19
      frameworks/Scala/play2-scala/play2-scala-anorm/app/controllers/Application.scala
  3. 5 5
      frameworks/Scala/play2-scala/play2-scala-anorm/app/models/World.scala
  4. 4 4
      frameworks/Scala/play2-scala/play2-scala-anorm/app/utils/DbOperation.scala
  5. 5 3
      frameworks/Scala/play2-scala/play2-scala-anorm/build.sbt
  6. 4 4
      frameworks/Scala/play2-scala/play2-scala-anorm/conf/application.conf
  7. 1 1
      frameworks/Scala/play2-scala/play2-scala-anorm/project/build.properties
  8. 1 1
      frameworks/Scala/play2-scala/play2-scala-anorm/project/plugins.sbt
  9. 25 0
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/app/AppLoader.scala
  10. 0 23
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/app/Filters.scala
  11. 16 25
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/app/controllers/Application.scala
  12. 9 5
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/build.sbt
  13. 5 2
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/application.conf
  14. 6 6
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/routes
  15. 1 1
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/build.properties
  16. 1 1
      frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/plugins.sbt
  17. 0 23
      frameworks/Scala/play2-scala/play2-scala-slick/app/Filters.scala
  18. 12 19
      frameworks/Scala/play2-scala/play2-scala-slick/app/controllers/Application.scala
  19. 3 3
      frameworks/Scala/play2-scala/play2-scala-slick/app/models/Fortune.scala
  20. 7 5
      frameworks/Scala/play2-scala/play2-scala-slick/app/models/World.scala
  21. 4 3
      frameworks/Scala/play2-scala/play2-scala-slick/build.sbt
  22. 6 4
      frameworks/Scala/play2-scala/play2-scala-slick/conf/application.conf
  23. 1 1
      frameworks/Scala/play2-scala/play2-scala-slick/project/build.properties
  24. 1 1
      frameworks/Scala/play2-scala/play2-scala-slick/project/plugins.sbt
  25. 6 5
      frameworks/Scala/play2-scala/play2-scala/app/controllers/Application.scala
  26. 7 5
      frameworks/Scala/play2-scala/play2-scala/build.sbt
  27. 12 3
      frameworks/Scala/play2-scala/play2-scala/conf/application.conf
  28. 1 1
      frameworks/Scala/play2-scala/play2-scala/project/build.properties
  29. 1 1
      frameworks/Scala/play2-scala/play2-scala/project/plugins.sbt
  30. 1 2
      frameworks/Scala/play2-scala/setup_scala.sh

+ 0 - 23
frameworks/Scala/play2-scala/play2-scala-anorm/app/Filters.scala

@@ -1,23 +0,0 @@
-import javax.inject.{Singleton, Inject}
-
-import play.api.http.HttpFilters
-import play.api.mvc.{RequestHeader, EssentialAction, EssentialFilter}
-import play.api.libs.concurrent.Execution.Implicits.defaultContext
-import play.mvc.Http
-
-@Singleton()
-class Filters @Inject() (headerFilter: HeaderFilter) extends HttpFilters {
-  override def filters: Seq[EssentialFilter] = Seq(
-    headerFilter)
-}
-
-@Singleton
-class HeaderFilter extends EssentialFilter {
-  def apply(next: EssentialAction) = new EssentialAction {
-    def apply(request: RequestHeader) = {
-      next(request).map(result =>
-        result.withHeaders(Http.HeaderNames.SERVER -> "EXAMPLE")  // Only here to address the WARN about this header.
-      )
-    }
-  }
-}

+ 12 - 19
frameworks/Scala/play2-scala/play2-scala-anorm/app/controllers/Application.scala

@@ -3,18 +3,18 @@ package controllers
 import javax.inject.{Inject, Singleton}
 
 import play.api.mvc._
+import play.mvc.Http
 import play.api.libs.json.Json
 import java.util.concurrent._
 import models.{WorldDAO, FortunesDAO, World, Fortune}
 import utils.DbOperation
-import scala.concurrent.Future
-
-import play.api.libs.concurrent.Execution.Implicits._
+import scala.concurrent.{Future, ExecutionContext}
 
 @Singleton()
-class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO, dbOperation: DbOperation)  extends Controller {
+class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO, dbOperation: DbOperation, val controllerComponents: ControllerComponents)(implicit ec: ExecutionContext)
+  extends BaseController {
 
-  // Anorm code
+  val defaultHeader = Http.HeaderNames.SERVER -> "Play Framework"
 
   def getRandomWorlds(n: Int): Future[Seq[World]] = dbOperation.asyncDbOp { implicit connection =>
     for (_ <- 1 to n) yield {
@@ -39,22 +39,15 @@ class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO, dbOpe
     ThreadLocalRandom.current().nextInt(TestDatabaseRows) + 1
   }
 
-  // Test seems picky about headers.  Doesn't like character set being there for JSON.  Always wants Server header set.
-  // There is a Filter which adds the Server header for all types.  Below I set Content-Type as needed to get rid of
-  // warnings.
-
-  // Easy ones
   case class HelloWorld(message: String)
 
   def getJsonMessage = Action {
     val helloWorld = HelloWorld(message = "Hello, World!")
-    Ok(Json.toJson(helloWorld)(Json.writes[HelloWorld])).withHeaders(CONTENT_TYPE -> "application/json")
+    Ok(Json.toJson(helloWorld)(Json.writes[HelloWorld])).withHeaders(defaultHeader)
   }
 
   val plaintext = Action {
-    // default headers are correct according to docs: charset included.
-    // BUT the test harness has a WARN state and says we don't need it.
-    Ok("Hello, World!").withHeaders(CONTENT_TYPE -> "text/plain")
+    Ok("Hello, World!").withHeaders(defaultHeader).as("text/plain")
   }
 
   // Common code between Scala database code
@@ -65,28 +58,28 @@ class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO, dbOpe
 
   def db = Action.async {
     getRandomWorlds(1).map { worlds =>
-      Ok(Json.toJson(worlds.head)).withHeaders(CONTENT_TYPE -> "application/json")
+      Ok(Json.toJson(worlds.head)).withHeaders(defaultHeader)
     }
   }
 
   def queries(countString: String) = Action.async {
     val n = parseCount(countString)
     getRandomWorlds(n).map { worlds =>
-      Ok(Json.toJson(worlds)).withHeaders(CONTENT_TYPE -> "application/json")
+      Ok(Json.toJson(worlds)).withHeaders(defaultHeader)
     }
   }
 
   def fortunes() = Action.async {
     getFortunes.map { dbFortunes =>
       val appendedFortunes =  Fortune(0, "Additional fortune added at request time.") :: dbFortunes.to[List]
-      Ok(views.html.fortune(appendedFortunes)).withHeaders(CONTENT_TYPE -> "text/html")
+      Ok(views.html.fortune(appendedFortunes)).withHeaders(defaultHeader).as(HTML)
     }
   }
 
   def update(queries: String) = Action.async {
     val n = parseCount(queries)
     updateWorlds(n).map { worlds =>
-      Ok(Json.toJson(worlds)).withHeaders(CONTENT_TYPE -> "application/json")
+      Ok(Json.toJson(worlds)).withHeaders(defaultHeader)
     }
   }
 
@@ -103,4 +96,4 @@ class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO, dbOpe
     }
   }
 
-}
+}

+ 5 - 5
frameworks/Scala/play2-scala/play2-scala-anorm/app/models/World.scala

@@ -9,7 +9,7 @@ import play.api.db.Database
 import play.api.libs.json._
 import play.db.NamedDatabase
 
-case class World(id: Id[Long], randomNumber: Long)
+case class World(id: Long, randomNumber: Long)
 
 @Singleton()
 class WorldDAO @Inject()(@NamedDatabase("hello_world") protected val db: Database) {
@@ -19,7 +19,7 @@ class WorldDAO @Inject()(@NamedDatabase("hello_world") protected val db: Databas
   private val simpleRowParser = {
     get[Long]("world.id") ~
     get[Long]("world.randomNumber") map {
-      case id~randomNumber => World(Id(id), randomNumber)
+      case id~randomNumber => World(id, randomNumber)
     }
   }
 
@@ -31,7 +31,7 @@ class WorldDAO @Inject()(@NamedDatabase("hello_world") protected val db: Databas
   }
 
   def updateRandom(world: World)(implicit connection: Connection) {
-    SQL"UPDATE World SET randomNumber = ${world.randomNumber} WHERE id = ${world.id.get}".executeUpdate()
+    SQL"UPDATE World SET randomNumber = ${world.randomNumber} WHERE id = ${world.id}".executeUpdate()
   }
 }
 
@@ -42,9 +42,9 @@ object WorldJsonHelpers {
   implicit val toJson = new Writes[World] {
     def writes(w: World): JsValue = {
       Json.obj(
-        "id" -> w.id.get,
+        "id" -> w.id,
         "randomNumber" -> w.randomNumber
       )
     }
   }
-}
+}

+ 4 - 4
frameworks/Scala/play2-scala/play2-scala-anorm/app/utils/DbOperation.scala

@@ -16,11 +16,11 @@ class DbOperation @Inject() (@NamedDatabase("hello_world") protected val db: Dat
 
   private val maxDbOperations = configuration.underlying.getInt("max-db-ops")
 
-  private val partitionCount = configuration.getInt("db.hello_world.partitionCount").getOrElse(2)
+  private val partitionCount = configuration.getOptional[Int]("db.hello_world.partitionCount").getOrElse(2)
   private val maxConnections =
-    partitionCount * configuration.getInt("db.hello_world.maxConnectionsPerPartition").getOrElse(5)
+    partitionCount * configuration.getOptional[Int]("db.hello_world.maxConnectionsPerPartition").getOrElse(5)
   private val minConnections =
-    partitionCount * configuration.getInt("db.hello_world.minConnectionsPerPartition").getOrElse(5)
+    partitionCount * configuration.getOptional[Int]("db.hello_world.minConnectionsPerPartition").getOrElse(5)
 
   private val tpe = new ThreadPoolExecutor(minConnections, maxConnections,
     0L, TimeUnit.MILLISECONDS,
@@ -46,4 +46,4 @@ class DbOperation @Inject() (@NamedDatabase("hello_world") protected val db: Dat
     }(dbEc)
   }
 
-}
+}

+ 5 - 3
frameworks/Scala/play2-scala/play2-scala-anorm/build.sbt

@@ -2,14 +2,16 @@ name := "play2-scala-anorm"
 
 version := "1.0-SNAPSHOT"
 
-scalaVersion := "2.11.7"
+scalaVersion := "2.12.3"
 
 lazy val root = (project in file(".")).enablePlugins(PlayScala)
 
 libraryDependencies ++= Seq(
   jdbc,
-  "com.typesafe.play" %% "anorm" % "2.4.0",
-  "mysql" % "mysql-connector-java" % "5.1.38")
+  "com.typesafe.play" %% "anorm" % "2.5.3",
+  "mysql" % "mysql-connector-java" % "5.1.44"
+)
+libraryDependencies += guice
 
 resolvers += "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases"
 

+ 4 - 4
frameworks/Scala/play2-scala/play2-scala-anorm/conf/application.conf

@@ -9,7 +9,7 @@
 # This must be changed for production, but we recommend not changing it in this file.
 #
 # See http://www.playframework.com/documentation/latest/ApplicationSecret for more details.
-play.crypto.secret = "RItx1I:80?W@]8GAtPDuF8Ydd3mXM85p/<7og]Q;uBOdijQAauRDgu73B6`wQP59"
+play.http.secret.key = "RItx1I:80?W@]8GAtPDuF8Ydd3mXM85p/<7og]Q;uBOdijQAauRDgu73B6`wQP59"
 
 # The application languages
 # ~~~~~
@@ -41,7 +41,7 @@ max-db-ops = 1024
 # You can expose this datasource via JNDI if needed (Useful for JPA)
 # db.default.jndiName=DefaultDS
 db.hello_world.driver= com.mysql.jdbc.Driver
-db.hello_world.url="jdbc:mysql://127.0.0.1:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
+db.hello_world.url="jdbc:mysql://127.0.0.1:3306/hello_world?alwaysSendSetIsolation=false&avoidCheckOnDuplicateKeyUpdateInSQL=true&cacheCallableStmts=true&cachePrepStmts=true&cacheRSMetadata=true&cacheServerConfiguration=true&characterEncoding=UTF-8&dontTrackOpenResources=true&elideSetAutoCommits=true&jdbcCompliantTruncation=false&maintainTimeStats=false&prepStmtCacheSize=500&prepStmtCacheSqlLimit=2048&useUnbufferedInput=false&useReadAheadInput=false&useLocalSessionState=true&useServerPrepStmts&useSSL=false&rewriteBatchedStatements=true&traceProtocol=false&zeroDateTimeBehavior=convertToNull"
 db.hello_world.username=benchmarkdbuser
 db.hello_world.password=benchmarkdbpass
 db.hello_world.jndiName=DefaultDS
@@ -61,9 +61,9 @@ db.hello_world.minConnectionsPerPartition=64
 # Evolutions
 # ~~~~~
 # You can disable evolutions if needed
-# play.evolutions.enabled=false
+play.evolutions.enabled=false
 
 # You can disable evolutions for a specific datasource if necessary
 # play.evolutions.db.default.enabled=false
 
-
+play.filters.enabled=[]

+ 1 - 1
frameworks/Scala/play2-scala/play2-scala-anorm/project/build.properties

@@ -1 +1 @@
-sbt.version=0.13.11
+sbt.version=1.0.2

+ 1 - 1
frameworks/Scala/play2-scala/play2-scala-anorm/project/plugins.sbt

@@ -2,4 +2,4 @@
 logLevel := Level.Warn
 
 // Use the Play sbt plugin for Play projects
-addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.5.14")
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.6")

+ 25 - 0
frameworks/Scala/play2-scala/play2-scala-reactivemongo/app/AppLoader.scala

@@ -0,0 +1,25 @@
+import controllers.AssetsComponents
+import play.api.{controllers => _, _}
+import router.Routes
+import routing.Router
+import ApplicationLoader.Context
+
+import com.softwaremill.macwire._
+import play.modules.reactivemongo.ReactiveMongoApiFromContext
+
+class AppLoader extends ApplicationLoader {
+  def load(context: Context) = new AppComponents(context).application
+}
+
+class AppComponents(context: Context)
+  extends ReactiveMongoApiFromContext(context)
+  with AssetsComponents {
+
+  override lazy val router: Router = new Routes(
+    httpErrorHandler,
+    wire[controllers.Application],
+    wire[controllers.Assets]
+  )
+
+  lazy val httpFilters = Seq.empty
+}

+ 0 - 23
frameworks/Scala/play2-scala/play2-scala-reactivemongo/app/Filters.scala

@@ -1,23 +0,0 @@
-import javax.inject.{Singleton, Inject}
-
-import play.api.http.HttpFilters
-import play.api.mvc.{RequestHeader, EssentialAction, EssentialFilter}
-import play.api.libs.concurrent.Execution.Implicits.defaultContext
-import play.mvc.Http
-
-@Singleton()
-class Filters @Inject() (headerFilter: HeaderFilter) extends HttpFilters {
-  override def filters: Seq[EssentialFilter] = Seq(
-    headerFilter)
-}
-
-@Singleton
-class HeaderFilter extends EssentialFilter {
-  def apply(next: EssentialAction) = new EssentialAction {
-    def apply(request: RequestHeader) = {
-      next(request).map(result =>
-        result.withHeaders(Http.HeaderNames.SERVER -> "EXAMPLE")  // Only here to address the WARN about this header.
-      )
-    }
-  }
-}

+ 16 - 25
frameworks/Scala/play2-scala/play2-scala-reactivemongo/app/controllers/Application.scala

@@ -1,25 +1,23 @@
 package controllers
 
 import java.util.concurrent.ThreadLocalRandom
-import javax.inject.{Singleton, Inject}
+import scala.concurrent.{Future, ExecutionContext}
 
 import play.api.libs.json.{JsObject, Json, JsValue}
-import play.api.libs.concurrent.Execution.Implicits.defaultContext
-import reactivemongo.api.ReadPreference
-
-import scala.concurrent.Future
-
-import play.api.mvc.{ Action, Controller }
+import play.api.mvc._
+import play.mvc.Http
 
+import reactivemongo.api.ReadPreference
+import reactivemongo.play.json.collection.JSONCollection
 import play.modules.reactivemongo.{
-MongoController, ReactiveMongoApi, ReactiveMongoComponents
+  ReactiveMongoApi, ReactiveMongoComponents, MongoController
 }
 import play.modules.reactivemongo.json._
-import play.modules.reactivemongo.json.collection.JSONCollection
 
-@Singleton
-class Application @Inject() (val reactiveMongoApi: ReactiveMongoApi)
-  extends Controller with MongoController with ReactiveMongoComponents {
+class Application (val controllerComponents: ControllerComponents, reactiveMongoApi: ReactiveMongoApi)(implicit ec: ExecutionContext)
+  extends BaseController {
+
+  val defaultHeader = Http.HeaderNames.SERVER -> "Play Framework"
 
   private def worldCollection: JSONCollection = reactiveMongoApi.db.collection[JSONCollection]("world")
   private def fortuneCollection: JSONCollection = reactiveMongoApi.db.collection[JSONCollection]("fortune")
@@ -67,22 +65,15 @@ class Application @Inject() (val reactiveMongoApi: ReactiveMongoApi)
     ThreadLocalRandom.current().nextInt(TestDatabaseRows) + 1
   }
 
-  // Test seems picky about headers.  Doesn't like character set being there for JSON.  Always wants Server header set.
-  // There is a Filter which adds the Server header for all types.  Below I set Content-Type as needed to get rid of
-  // warnings.
-
-  // Easy ones
   case class HelloWorld(message: String)
 
   def getJsonMessage = Action {
     val helloWorld = HelloWorld(message = "Hello, World!")
-    Ok(Json.toJson(helloWorld)(Json.writes[HelloWorld])).withHeaders(CONTENT_TYPE -> "application/json")
+    Ok(Json.toJson(helloWorld)(Json.writes[HelloWorld])).withHeaders(defaultHeader)
   }
 
   val plaintext = Action {
-    // default headers are correct according to docs: charset included.
-    // BUT the test harness has a WARN state and says we don't need it.
-    Ok("Hello, World!").withHeaders(CONTENT_TYPE -> "text/plain")
+    Ok("Hello, World!").withHeaders(defaultHeader).as("text/plain")
   }
 
   // Semi-Common code between Scala database code
@@ -91,14 +82,14 @@ class Application @Inject() (val reactiveMongoApi: ReactiveMongoApi)
 
   def doDb = Action.async {
     getRandomWorld.map { worlds =>
-      Ok(Json.toJson(worlds.head)).withHeaders(CONTENT_TYPE -> "application/json")
+      Ok(Json.toJson(worlds.head)).withHeaders(defaultHeader)
     }
   }
 
   def queries(countString: String) = Action.async {
     val n = parseCount(countString)
     getRandomWorlds(n).map { worlds =>
-      Ok(Json.toJson(worlds)).withHeaders(CONTENT_TYPE -> "application/json")
+      Ok(Json.toJson(worlds)).withHeaders(defaultHeader)
     }
   }
 
@@ -112,14 +103,14 @@ class Application @Inject() (val reactiveMongoApi: ReactiveMongoApi)
 
       val sorted = appendedFortunes.sortBy(byMessage(_))
 
-      Ok(views.html.fortune(sorted)).withHeaders(CONTENT_TYPE -> "text/html")
+      Ok(views.html.fortune(sorted)).withHeaders(defaultHeader).as(HTML)
     }
   }
 
   def update(queries: String) = Action.async {
     val n = parseCount(queries)
     updateWorlds(n).map { worlds =>
-      Ok(Json.toJson(worlds)).withHeaders(CONTENT_TYPE -> "application/json")
+      Ok(Json.toJson(worlds)).withHeaders(defaultHeader)
     }
   }
 

+ 9 - 5
frameworks/Scala/play2-scala/play2-scala-reactivemongo/build.sbt

@@ -2,12 +2,16 @@ name := "play2-scala-reactivemongo"
 
 version := "1.0-SNAPSHOT"
 
-scalaVersion := "2.11.7"
+scalaVersion := "2.12.3"
 
-lazy val root = (project in file(".")).enablePlugins(PlayScala)
+lazy val root =
+  (project in file(".")).
+  settings(routesGenerator := InjectedRoutesGenerator).
+  enablePlugins(PlayScala)
 
 libraryDependencies ++= Seq(
-  "org.reactivemongo" %% "play2-reactivemongo" % "0.11.9",
-  "org.reactivemongo" %% "reactivemongo-play-json" % "0.11.9"
+  "org.reactivemongo" %% "play2-reactivemongo" % "0.12.7-play26",
+  "org.reactivemongo" %% "reactivemongo-play-json" % "0.12.7-play26",
+  "com.softwaremill.macwire" %% "macros" % "2.3.0",
+  "com.softwaremill.macwire" %% "util" % "2.3.0"
 )
-

+ 5 - 2
frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/application.conf

@@ -8,7 +8,7 @@
 # This must be changed for production, but we recommend not changing it in this file.
 #
 # See http://www.playframework.com/documentation/latest/ApplicationSecret for more details.
-play.crypto.secret = "RItx1I:80?W@]8GAtPDuF8Ydd3mXM85p/<7og]Q;uBOdijQAauRDgu73B6`wQP59"
+play.http.secret.key = "RItx1I:80?W@]8GAtPDuF8Ydd3mXM85p/<7og]Q;uBOdijQAauRDgu73B6`wQP59"
 
 # The application languages
 # ~~~~~
@@ -38,7 +38,7 @@ play.i18n.langs = [ "en" ]
 # Evolutions
 # ~~~~~
 # You can disable evolutions if needed
-# play.evolutions.enabled=false
+play.evolutions.enabled=false
 
 # You can disable evolutions for a specific datasource if necessary
 # play.evolutions.db.default.enabled=false
@@ -47,4 +47,7 @@ play.modules.enabled += "play.modules.reactivemongo.ReactiveMongoModule"
 
 mongodb.servers = ["TFB-database:27017"]
 mongodb.db = "hello_world"
+mongodb.uri = "mongodb://TFB-database:27017/hello_world"
 
+play.filters.enabled=[]
+play.application.loader=AppLoader

+ 6 - 6
frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/routes

@@ -3,12 +3,12 @@
 # ~~~~
 
 # Home page
-GET     /json                           @controllers.Application.getJsonMessage
-GET     /db                             @controllers.Application.doDb
-GET     /queries                        @controllers.Application.queries(queries: String ?= "1")
-GET     /fortunes                       @controllers.Application.fortunes
-GET     /update                         @controllers.Application.update(queries ?= "1")
-GET     /plaintext                      @controllers.Application.plaintext
+GET     /json                           controllers.Application.getJsonMessage
+GET     /db                             controllers.Application.doDb
+GET     /queries                        controllers.Application.queries(queries: String ?= "1")
+GET     /fortunes                       controllers.Application.fortunes
+GET     /update                         controllers.Application.update(queries ?= "1")
+GET     /plaintext                      controllers.Application.plaintext
 
 # Map static resources from the /public folder to the /assets URL path
 GET     /assets/*file                   controllers.Assets.at(path="/public", file)

+ 1 - 1
frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/build.properties

@@ -1 +1 @@
-sbt.version=0.13.9
+sbt.version=1.0.2

+ 1 - 1
frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/plugins.sbt

@@ -1,2 +1,2 @@
 // Use the Play sbt plugin for Play projects
-addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.4.6")
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.6")

+ 0 - 23
frameworks/Scala/play2-scala/play2-scala-slick/app/Filters.scala

@@ -1,23 +0,0 @@
-import javax.inject.{Singleton, Inject}
-
-import play.api.http.HttpFilters
-import play.api.mvc.{RequestHeader, EssentialAction, EssentialFilter}
-import play.api.libs.concurrent.Execution.Implicits.defaultContext
-import play.mvc.Http
-
-@Singleton()
-class Filters @Inject() (headerFilter: HeaderFilter) extends HttpFilters {
-  override def filters: Seq[EssentialFilter] = Seq(
-    headerFilter)
-}
-
-@Singleton
-class HeaderFilter extends EssentialFilter {
-  def apply(next: EssentialAction) = new EssentialAction {
-    def apply(request: RequestHeader) = {
-      next(request).map(result =>
-        result.withHeaders(Http.HeaderNames.SERVER -> "EXAMPLE")  // Only here to address the WARN about this header.
-      )
-    }
-  }
-}

+ 12 - 19
frameworks/Scala/play2-scala/play2-scala-slick/app/controllers/Application.scala

@@ -3,16 +3,16 @@ package controllers
 import java.util.concurrent._
 import javax.inject.{Singleton, Inject}
 import play.api.mvc._
+import play.mvc.Http
 import play.api.libs.json.Json
 import models._
-import scala.concurrent.Future
-
-import play.api.libs.concurrent.Execution.Implicits._
+import scala.concurrent.{Future, ExecutionContext}
 
 @Singleton()
-class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO) extends Controller {
+class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO, val controllerComponents: ControllerComponents)(implicit ec: ExecutionContext)
+  extends BaseController {
 
-  // Slick code
+  val defaultHeader = Http.HeaderNames.SERVER -> "Play Framework"
 
   def getRandomWorlds(n: Int): Future[Seq[World]] = {
     val worlds: Seq[Future[World]] = for (_ <- 1 to n) yield {
@@ -39,22 +39,15 @@ class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO) exten
     ThreadLocalRandom.current().nextInt(TestDatabaseRows) + 1
   }
 
-  // Test seems picky about headers.  Doesn't like character set being there for JSON.  Always wants Server header set.
-  // There is a Filter which adds the Server header for all types.  Below I set Content-Type as needed to get rid of
-  // warnings.
-
-  // Easy ones
   case class HelloWorld(message: String)
 
   def getJsonMessage = Action {
     val helloWorld = HelloWorld(message = "Hello, World!")
-    Ok(Json.toJson(helloWorld)(Json.writes[HelloWorld])).withHeaders(CONTENT_TYPE -> "application/json")
+    Ok(Json.toJson(helloWorld)(Json.writes[HelloWorld])).withHeaders(defaultHeader)
   }
 
   val plaintext = Action {
-    // default headers are correct according to docs: charset included.
-    // BUT the test harness has a WARN state and says we don't need it.
-    Ok("Hello, World!").withHeaders(CONTENT_TYPE -> "text/plain")
+    Ok("Hello, World!").withHeaders(defaultHeader).as("text/plain")
   }
 
   // Common code between Scala database code
@@ -65,28 +58,28 @@ class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO) exten
 
   def db = Action.async {
     getRandomWorlds(1).map { worlds =>
-      Ok(Json.toJson(worlds.head)).withHeaders(CONTENT_TYPE -> "application/json")
+      Ok(Json.toJson(worlds.head)).withHeaders(defaultHeader)
     }
   }
 
   def queries(countString: String) = Action.async {
     val n = parseCount(countString)
     getRandomWorlds(n).map { worlds =>
-      Ok(Json.toJson(worlds)).withHeaders(CONTENT_TYPE -> "application/json")
+      Ok(Json.toJson(worlds)).withHeaders(defaultHeader)
     }
   }
 
   def fortunes() = Action.async {
     getFortunes.map { dbFortunes =>
       val appendedFortunes =  Fortune(0, "Additional fortune added at request time.") :: dbFortunes.to[List]
-      Ok(views.html.fortune(appendedFortunes)).withHeaders(CONTENT_TYPE -> "text/html")
+      Ok(views.html.fortune(appendedFortunes)).withHeaders(defaultHeader).as(HTML)
     }
   }
 
   def update(queries: String) = Action.async {
     val n = parseCount(queries)
     updateWorlds(n).map { worlds =>
-      Ok(Json.toJson(worlds)).withHeaders(CONTENT_TYPE -> "application/json")
+      Ok(Json.toJson(worlds)).withHeaders(defaultHeader)
     }
   }
 
@@ -103,4 +96,4 @@ class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO) exten
     }
   }
 
-}
+}

+ 3 - 3
frameworks/Scala/play2-scala/play2-scala-slick/app/models/Fortune.scala

@@ -4,7 +4,7 @@ import javax.inject.{Inject, Singleton}
 
 import play.api.db.slick.{HasDatabaseConfigProvider, DatabaseConfigProvider}
 import play.db.NamedDatabase
-import slick.driver.JdbcProfile
+import slick.jdbc.JdbcProfile
 
 import scala.concurrent.Future
 
@@ -13,7 +13,7 @@ case class Fortune(id: Long, message: String)
 @Singleton()
 class FortunesDAO @Inject()(@NamedDatabase("hello_world") protected val dbConfigProvider: DatabaseConfigProvider) extends HasDatabaseConfigProvider[JdbcProfile] {
 
-  import driver.api._
+  import profile.api._
 
   private val Fortunes = TableQuery[FortunesTable]
 
@@ -31,4 +31,4 @@ class FortunesDAO @Inject()(@NamedDatabase("hello_world") protected val dbConfig
     def * = (id, message) <>(Fortune.tupled, Fortune.unapply)
 
   }
-}
+}

+ 7 - 5
frameworks/Scala/play2-scala/play2-scala-slick/app/models/World.scala

@@ -7,13 +7,15 @@ import scala.concurrent.Future
 import javax.inject.{Singleton, Inject}
 import play.api.db.slick.DatabaseConfigProvider
 import play.api.db.slick.HasDatabaseConfigProvider
-import play.api.libs.concurrent.Execution.Implicits.defaultContext
 import play.db.NamedDatabase
-import slick.driver.JdbcProfile
+import slick.jdbc.JdbcProfile
+import scala.concurrent.ExecutionContext
 
 @Singleton()
-class WorldDAO @Inject()(@NamedDatabase("hello_world") protected val dbConfigProvider: DatabaseConfigProvider) extends HasDatabaseConfigProvider[JdbcProfile] {
-  import driver.api._
+class WorldDAO @Inject()(@NamedDatabase("hello_world") protected val dbConfigProvider: DatabaseConfigProvider) (implicit ec: ExecutionContext)
+  extends HasDatabaseConfigProvider[JdbcProfile] {
+
+  import profile.api._
 
   private val Worlds = TableQuery[WorldsTable]
 
@@ -50,4 +52,4 @@ object WorldJsonHelpers {
       )
     }
   }
-}
+}

+ 4 - 3
frameworks/Scala/play2-scala/play2-scala-slick/build.sbt

@@ -2,12 +2,13 @@ name := "play2-scala-slick"
 
 version := "1.0-SNAPSHOT"
 
-scalaVersion := "2.11.7"
+scalaVersion := "2.12.3"
 
 lazy val root = (project in file(".")).enablePlugins(PlayScala)
 
 libraryDependencies ++= Seq(
-  "com.typesafe.play" %% "play-slick" % "1.1.1",
-  "mysql" % "mysql-connector-java" % "5.1.38",
+  "com.typesafe.play" %% "play-slick" % "3.0.2",
+  "mysql" % "mysql-connector-java" % "5.1.44",
   filters
 )
+libraryDependencies += guice

+ 6 - 4
frameworks/Scala/play2-scala/play2-scala-slick/conf/application.conf

@@ -8,11 +8,11 @@
 # ~~~~~
 # The secret key is used to secure cryptographics functions.
 # If you deploy your application to several instances be sure to use the same key!
-application.secret="RItx1I:80?W@]8GAtPDuF8Ydd3mXM85p/<7og]Q;uBOdijQAauRDgu73B6`wQP59"
+play.http.secret.key="RItx1I:80?W@]8GAtPDuF8Ydd3mXM85p/<7og]Q;uBOdijQAauRDgu73B6`wQP59"
 
 # The application languages
 # ~~~~~
-application.langs="en"
+play.i18n.langs=["en"]
 
 # Global object class
 # ~~~~~
@@ -23,9 +23,9 @@ application.langs="en"
 # Database configuration
 # ~~~~~ 
 
-slick.dbs.hello_world.driver="slick.driver.MySQLDriver$"
+slick.dbs.hello_world.profile="slick.jdbc.MySQLProfile$"
 slick.dbs.hello_world.db.driver="com.mysql.jdbc.Driver"
-slick.dbs.hello_world.db.url="jdbc:mysql://127.0.0.1:3306/hello_world?jdbcCompliantTruncation=false&elideSetAutoCommits=true&useLocalSessionState=true&cachePrepStmts=true&cacheCallableStmts=true&alwaysSendSetIsolation=false&prepStmtCacheSize=4096&cacheServerConfiguration=true&prepStmtCacheSqlLimit=2048&zeroDateTimeBehavior=convertToNull&traceProtocol=false&useUnbufferedInput=false&useReadAheadInput=false&maintainTimeStats=false&useServerPrepStmts&cacheRSMetadata=true"
+slick.dbs.hello_world.db.url="jdbc:mysql://127.0.0.1:3306/hello_world?alwaysSendSetIsolation=false&avoidCheckOnDuplicateKeyUpdateInSQL=true&cacheCallableStmts=true&cachePrepStmts=true&cacheRSMetadata=true&cacheServerConfiguration=true&characterEncoding=UTF-8&dontTrackOpenResources=true&elideSetAutoCommits=true&jdbcCompliantTruncation=false&maintainTimeStats=false&prepStmtCacheSize=500&prepStmtCacheSqlLimit=2048&useUnbufferedInput=false&useReadAheadInput=false&useLocalSessionState=true&useServerPrepStmts&useSSL=false&rewriteBatchedStatements=true&traceProtocol=false&zeroDateTimeBehavior=convertToNull"
 slick.dbs.hello_world.db.user="benchmarkdbuser"
 slick.dbs.hello_world.db.password="benchmarkdbpass"
 slick.dbs.hello_world.db.connectionPool = HikariCP
@@ -56,3 +56,5 @@ play {
     }
   }
 }
+
+play.filters.enabled=[]

+ 1 - 1
frameworks/Scala/play2-scala/play2-scala-slick/project/build.properties

@@ -1 +1 @@
-sbt.version=0.13.9
+sbt.version=1.0.2

+ 1 - 1
frameworks/Scala/play2-scala/play2-scala-slick/project/plugins.sbt

@@ -5,4 +5,4 @@ logLevel := Level.Warn
 resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"
 
 // Use the Play sbt plugin for Play projects
-addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.4.6")
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.6")

+ 6 - 5
frameworks/Scala/play2-scala/play2-scala/app/controllers/Application.scala

@@ -10,16 +10,17 @@ import play.mvc.Http
 class Application @Inject() (cc: ControllerComponents)
 extends AbstractController(cc) {
 
-  implicit val helloWorldWrites = Json.writes[HelloWorld]
+  implicit final val helloWorldWrites = Json.writes[HelloWorld]
+
+  val defaultHeader = Http.HeaderNames.SERVER -> "Play Framework"
 
   def getJsonMessage = Action {
-    val helloWorld = HelloWorld(message = "Hello, World!")
-    Ok(Json.toJson(helloWorld)).withHeaders(Http.HeaderNames.SERVER -> "Play Framework")
+    Ok( Json.toJson(HelloWorld()) ).withHeaders(defaultHeader)
   }
 
   val plaintext = Action {
-    Ok("Hello, World!").withHeaders(Http.HeaderNames.SERVER -> "Play Framework")
+    Ok("Hello, World!").withHeaders(defaultHeader).as("text/plain")
   }
 }
 
-case class HelloWorld(message: String)
+case class HelloWorld(message: String = "Hello, World!")

+ 7 - 5
frameworks/Scala/play2-scala/play2-scala/build.sbt

@@ -1,11 +1,13 @@
 name := "play2-scala"
 
-version := "2.6.0"
+version := "1.0-SNAPSHOT"
 
-scalaVersion := "2.11.11"
+scalaVersion := "2.12.3"
 
-val root = (project in file(".")).enablePlugins(PlayScala)
+val root =
+  (project in file(".")).
+  enablePlugins(PlayScala, PlayNettyServer).
+  disablePlugins(PlayAkkaHttpServer)
 
-libraryDependencies += "com.typesafe.play" %% "play-json" % "2.6.0"
+libraryDependencies += "com.typesafe.play" %% "play-json" % "2.6.6"
 libraryDependencies += guice
-

+ 12 - 3
frameworks/Scala/play2-scala/play2-scala/conf/application.conf

@@ -38,14 +38,23 @@ play.i18n.langs = [ "en" ]
 # Evolutions
 # ~~~~~
 # You can disable evolutions if needed
-# play.evolutions.enabled=false
+play.evolutions.enabled=false
 
 # You can disable evolutions for a specific datasource if necessary
 # play.evolutions.db.default.enabled=false
 
 play.server {
   netty {
-    transport = "native"   # should be "jdk" for non-Linux platforms
+    transport = "native"
+
+    option {
+      SO_BACKLOG = 128
+
+      child {
+        SO_KEEPALIVE = true
+        TCP_NODELAY = true
+      }
+    }
   }
 }
 
@@ -53,4 +62,4 @@ akka {
   log-dead-letters = off
 }
 
-play.filters.enabled=[]
+play.filters.enabled=[]

+ 1 - 1
frameworks/Scala/play2-scala/play2-scala/project/build.properties

@@ -1 +1 @@
-sbt.version=0.13.15
+sbt.version=1.0.2

+ 1 - 1
frameworks/Scala/play2-scala/play2-scala/project/plugins.sbt

@@ -2,4 +2,4 @@
 logLevel := Level.Warn
 
 // Use the Play sbt plugin for Play projects
-addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.0")
+addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.6")

+ 1 - 2
frameworks/Scala/play2-scala/setup_scala.sh

@@ -1,9 +1,8 @@
 #!/bin/bash
 
-fw_depends mysql java sbt
+fw_depends java sbt
 
 cd play2-scala
-sed -i "s|jdbc:mysql:\/\/.*:3306|jdbc:mysql://${DBHOST}:3306|g" ${TROOT}/play2-scala/conf/application.conf
 
 # Clear old running app.
 rm -rf ${TROOT}/play2-scala/target/universal/stage/RUNNING_PID