I'm trying a simple test application with Slick and the Play2 Framework, but the compiler keeps complaining the implicit session cannot be inferred.
Here is my Build.scala:
import sbt._
import Keys._
import play.Project._
object ApplicationBuild extends Build {
val appName = "dummy"
val appVersion = "1.0"
val appDependencies = Seq(
jdbc,
"mysql" % "mysql-connector-java" % "5.1.26",
"com.typesafe.slick" %% "slick" % "1.0.1"
)
val main = play.Project(appName, appVersion, appDependencies).settings(
// Add your own project settings here
)
}
And this is my Global singleton that holds my database connections:
package models
import play.api.Play.current
import play.api.db.DB
import slick.session.Session
import slick.driver.MySQLDriver.simple._
import scala.slick.session.Database.threadLocalSession
object Global {
lazy val database = Database.forDataSource(DB.getDataSource())
lazy val session = database.createSession()
}
And my controller:
package controllers
import scala.language.implicitConversions
import play.api._
import play.api.mvc._
import models.Global.session
import slick.driver.MySQLDriver.simple._
object Application extends Controller {
def index = Action {
/*slick.driver.MySQLDriver.simple.*/Query(Foo).foreach( _ => () ) // Do nothing for now
Ok(views.html.index("hola"))
}
object Foo extends Table[(Long, String, String)]("Foo") {
def * = column[Long]("id") ~ column[String]("bar1") ~ column[String]("bar2")
}
}
As you can see my Global.session val is imported, but it keeps saying no implicit session was found.
To make queries you need two things: connection to the database and a session, so your problem is how you define and use them.
With Database.threadLocalSession in scope, you can make your queries like this :
Database.forURL("jdbc:h2:mem:play", driver = "org.h2.Driver") withSession {
//create table
Foo.ddl.create
//insert data
Foo.insert((1.toLong,"foo","bar"))
//get data
val data : (Long,String,String) = (for{f<-Foo}yield(f)).first
}
or you can do it like this:
val database = Database.forDataSource(DB.getDataSource())
database.withSession{ implicit session : Session =>
Foo.ddl.create
Foo.insert((1.toLong,"foo","bar"))
val data : (Long,String,String) = (for{f<-Foo}yield(f)).first
}
I have create a test and it works fine, you can play with it:
"Foo should be creatable " in {
running(FakeApplication(additionalConfiguration = inMemoryDatabase())) {
val database = Database.forDataSource(DB.getDataSource())
database.withSession{ implicit session : Session =>
Foo.ddl.create
Foo.insert((1.toLong,"foo","bar"))
val data : (Long,String,String) = (for{f<-Foo}yield(f)).first
data._1 must equalTo(1)
}
}
}
Also you may look at here
Related
I have a task that will generate an output file based on several input files as well as some sbt settings. It's basically like a compiler where the result is determined by both input files and settings such as compiler flags. Therefore I need to regenerate the result if either the input files or the settings have changed.
This seems like a very common thing to me, and while I do have a solution that works, it seems ugly and long-winded. Is there a better (simpler and/or shorter) way to do it?
import java.nio.file.Path
import sbt.nio.Keys._
import sbt._
import sbt.Keys._
import sbt.nio.file.FileTreeView
import sjsonnew._
class StuffConfig
object StuffConfig {
implicit val fmt: JsonFormat[StuffConfig] = ??? // omitted
}
object StuffPlugin extends AutoPlugin {
object autoImport {
val generateStuff = taskKey[File]("generate Stuff")
val stuffConfig = settingKey[StuffConfig]("stuff config")
val stuffInputFiles = settingKey[Seq[Glob]]("stuff inputs")
val stuffOutput = settingKey[File]("stuff outputs")
}
def doTheThings(cfg: StuffConfig, files: Seq[Path]) = ??? // omitted
override def projectSettings: Seq[Def.Setting[_]] = {
import autoImport._
Seq(
generateStuff / fileInputs := stuffInputFiles.value,
generateStuff := {
val store = streams.value.cacheStoreFactory.make("stuffCache")
val filesChanged = generateStuff.inputFileChanges.hasChanges
val output = stuffOutput.value
Tracked.inputChanged[StuffConfig, File](store) { (configChanged, config) =>
if (configChanged || filesChanged || !output.exists) {
doTheThings(config, FileTreeView.default.list(stuffInputFiles.value).map(_._1))
}
stuffOutput.value
}.apply(stuffConfig.value)
}
)
}
}
I am trying to convert an svg image to a jpeg image in scala play framework.
I used batik and it worked ok.
Now I like to stream the output in the action result, instead of converting ByteArrayOutputStream to a
ByteArray which loads the entire output in memory.
How can I do that?
Here is the project code, which works without streaming the output:
build.sbt
name := "svg2png"
version := "1.0-SNAPSHOT"
lazy val root = (project in file(".")).enablePlugins(PlayScala)
resolvers += Resolver.sonatypeRepo("snapshots")
scalaVersion := "2.12.3"
libraryDependencies ++= Seq(
jdbc,
guice,
"org.apache.xmlgraphics" % "batik-transcoder" % "1.11",
"org.apache.xmlgraphics" % "batik-codec" % "1.11"
)
/project/plugins.sbt
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.6")
/project/build.properties
sbt.version=1.0.2
/conf/routes
GET / controllers.Application.index
GET /image controllers.Application.getImage
/conf/application.conf
play.filters.enabled += "play.filters.cors.CORSFilter"
play.filters {
hosts {
allowed = ["."]
}
headers {
contentSecurityPolicy = null
}
}
play.i18n {
langs = [ "en" ]
}
contexts {
imageService {
fork-join-executor {
parallelism-factor = 4.0
parallelism-max = 8
}
}
}
/app/controllers/Application.scala
package controllers
import play.api.mvc._
import javax.inject._
import scala.concurrent.ExecutionContext
#Singleton
class Application #Inject()(imageService: services.ImageService,
cc: ControllerComponents)(implicit exec: ExecutionContext) extends AbstractController(cc) {
def index = Action {
Ok("test app").as(HTML)
}
def getImage : Action[AnyContent] = Action.async {
imageService.getImage.map{res => Ok(res).as("image/jpeg") }
}
}
/app/services/ImageService.scala
package services
import java.io.{ByteArrayOutputStream, StringReader}
import com.google.inject.{Inject, Singleton}
import scala.concurrent.{ExecutionContext, Future}
import akka.actor.ActorSystem
import org.apache.batik.transcoder.image.JPEGTranscoder
import org.apache.batik.transcoder.TranscoderInput
import org.apache.batik.transcoder.TranscoderOutput
#Singleton
class ImageService #Inject()(actorSystem: ActorSystem) {
implicit val AnalyticsServiceExecutionContext: ExecutionContext = actorSystem.dispatchers.lookup("contexts.imageService")
def getImage: Future[Array[Byte]] = {
Future {
val t: JPEGTranscoder = new JPEGTranscoder
t.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, new java.lang.Float(0.8))
val imageSVGString: String =
"""<svg width="1000" height="1000" viewBox="0 0 1000 1000" version="1.1"
| xmlns="http://www.w3.org/2000/svg"
| xmlns:xlink="http://www.w3.org/1999/xlink">
| <circle cx="500" cy="500" r="300" fill="lightblue" />
|</svg>
""".stripMargin
val input: TranscoderInput = new TranscoderInput(new StringReader(imageSVGString))
val outputStream = new ByteArrayOutputStream
val output: TranscoderOutput = new TranscoderOutput(outputStream)
t.transcode(input, output)
outputStream.toByteArray
}
}
}
This works for me:
svg match {
case None => NotFound
case Some(svg) =>
val svgImage = new TranscoderInput(new StringReader(svg))
val pngOstream = new ByteArrayOutputStream
val outputPngImage = new TranscoderOutput(pngOstream)
val converter = fileExtension match {
case "png" => new PNGTranscoder()
case _ => new JPEGTranscoder()
}
if(converter.isInstanceOf[JPEGTranscoder]){
converter.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, (0.8).toFloat)
}
converter.transcode(svgImage, outputPngImage)
Ok(pngOstream.toByteArray).as("image/" + fileExtension)
}
I am trying to do some tests using ScalaTest + embedmongo + reactivemongo but I fail. My first problem is that after a test mongod process does not shut down, I have this message in console:
INFO: stopOrDestroyProcess: process has not exited
and tests are paused till I kill the process manually. That happens even if body of my test is empty. I am running windows 8.1.
The other issue is, that when I try to connect to db inside test using reactive mongo and insert anything to db I get this exception:
reactivemongo.core.errors.ConnectionNotInitialized: MongoError['Connection is missing metadata (like protocol version, etc.) The connection pool is probably being initialized.']
I have literally no idea how to set it up. Here is my test code:
package model
import com.github.simplyscala.MongoEmbedDatabase
import org.scalatest.{OptionValues, Matchers, BeforeAndAfter, FlatSpec}
import reactivemongo.api.MongoDriver
import reactivemongo.api.collections.bson.BSONCollection
import scala.concurrent.duration._
import reactivemongo.bson.BSONDocument
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
class MongoBookingRepositoryTest extends FlatSpec
with Matchers
with OptionValues
with MongoEmbedDatabase
with BeforeAndAfter {
"A MongoBookingRepository" should "..." in withEmbedMongoFixture(port = 12345) { mongoProps =>
val driver = new MongoDriver
val connection = driver.connection("localhost:12345" :: Nil)
val db = connection("testDatabase")
val collection = db.collection[BSONCollection]("bookings")
val future = collection.insert(BSONDocument("a" -> 5))
println(Await.result(future, 3.seconds))
driver.close()
connection.close()
}
}
In play2.4 I tried as below and it worked.
dependencies:
"org.reactivemongo" %% "play2-reactivemongo" % "0.11.7.play24",
"org.reactivemongo" %% "reactivemongo-extensions-json" % "0.11.7.play24",
// test
"org.scalatest" %% "scalatest" % "2.2.4" % Test,
"de.flapdoodle.embed" % "de.flapdoodle.embed.mongo" % "1.50.0" % Test,
"org.mockito" % "mockito-core" % "1.10.19" % Test
TestMongoSetup:
import de.flapdoodle.embed.mongo.config.{Net, MongodConfigBuilder}
import de.flapdoodle.embed.mongo.distribution.Version
import de.flapdoodle.embed.mongo.{MongodStarter, MongodProcess, MongodExecutable}
import de.flapdoodle.embed.process.runtime.Network
import org.mockito.Mockito._
import play.modules.reactivemongo.ReactiveMongoApi
import reactivemongo.api.MongoConnection.ParsedURI
import reactivemongo.api.{MongoConnectionOptions, MongoDriver, MongoConnection}
import scala.concurrent.ExecutionContext
trait TestMongoSetup {
private var port : Int = _
private var mongodExe: MongodExecutable = _
private var mongodProcess: MongodProcess = _
def start(intiAtPort: Int): Unit = {
port=intiAtPort
mongodExe = MongodStarter.getDefaultInstance.prepare(
new MongodConfigBuilder()
.version(Version.Main.V3_0)
.net(new Net(port, Network.localhostIsIPv6()))
.build()
)
mongodProcess = mongodExe.start()
}
def stop(): Unit = {
mongodProcess.stop()
mongodExe.stop()
}
def createConnection(): MongoConnection = {
val driver = new MongoDriver
driver.connection(ParsedURI(
hosts = List(("localhost", port)),
options = MongoConnectionOptions(),
ignoredOptions = List.empty[String],
db = None,
authenticate = None
))
}
def createMockedReactiveMongoApi(dbName: String)(implicit ctx: ExecutionContext): ReactiveMongoApi = {
val connection = createConnection()
val db = connection(dbName)
val api = mock(classOf[ReactiveMongoApi])
doReturn(db).when(api).db
doReturn(connection).when(api).connection
api
}
}
TestClass:
import db.TestMongoSetup
import models.dao.UserDAO
import org.scalatest._
import play.modules.reactivemongo.ReactiveMongoApi
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
class UserServiceTest extends FlatSpec with ShouldMatchers with GivenWhenThen with BeforeAndAfterAll with TestMongoSetup { private var mockedAPI: ReactiveMongoApi = _
var dao: UserDAO = _
val port : Int = 12345
override def beforeAll(): Unit = {
start(port)
mockedAPI = createMockedReactiveMongoApi("testDB")
dao = new UserDAO(mockedAPI)
}
override def afterAll(): Unit = {
mockedAPI.connection.actorSystem.shutdown()
mockedAPI.connection.actorSystem.awaitTermination()
stop()
}
"Check" should "check User object into DB" in {
Given("a user info")
val email = "xyx#abc.com"
val pwd= "abcddd"
When("it fetch from DB")
val fromDBUser = Await.result(dao.fetch(email,pwd), Duration.Inf)
Then("it should be fetched")
fromDBUser.get.email should equal(email)
}
}
withEmbedMongoFixture doesn't work very well.
Prefer use the "classic" way : https://github.com/SimplyScala/scalatest-embedmongo#basic-usage-mutable-way
For Mongo 3 use 2.3_SNAPSHOT version of the library.
I have this simple test Scala application, which a blocking http request:
build.sbt
name := "hello"
version := "1.0"
scalaVersion := "2.11.2"
libraryDependencies += "com.typesafe.play" %% "play-ws" % "2.4.0-M1"
Test.scala
import play.api.libs.json._
import play.api.libs.ws._
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
object Test {
def main(args: Array[String]) = {
val wsClient = WS.client
val body = getBody(wsClient.url("http://example.com/").get())
println(s"body: $body")
}
def getBody(future: Future[WSResponse]) = {
val response = Await.result(future, Duration.Inf);
if (response.status != 200)
throw new Exception(response.statusText);
response.body
}
}
This application fails with:
Exception in thread "main" java.lang.RuntimeException: There is no started application
How to solve this issue?
EDIT for Play 2.5:
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import play.api.libs.ws._
import play.api.libs.ws.ahc.AhcWSClient
import scala.concurrent.Future
object Main {
import scala.concurrent.ExecutionContext.Implicits._
def main(args: Array[String]): Unit = {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
val wsClient = AhcWSClient()
call(wsClient)
.andThen { case _ => wsClient.close() }
.andThen { case _ => system.terminate() }
}
def call(wsClient: WSClient): Future[Unit] = {
wsClient.url("http://www.google.com").get().map { response =>
val statusText: String = response.statusText
println(s"Got a response $statusText")
}
}
}
Please see:
https://www.playframework.com/documentation/2.5.x/ScalaWS#using-wsclient
https://www.playframework.com/documentation/2.5.x/ScalaTestingWebServiceClients
for more detailed examples of standalone WSClient usage. If you are migrating from earlier versions, see https://www.playframework.com/documentation/2.5.x/Migration25#Play-WS-upgrades-to-AsyncHttpClient-2
For Play 2.4:
Do not use raw AsyncHttpClientConfig.Builder for HTTPS -- it does not configure a secure SSLContext with hostname validation.
You can create a new WSClient instance using the following code:
import play.api.libs.ws.ning._
import play.api.libs.ws._
val config = new NingAsyncHttpClientConfigBuilder(DefaultWSClientConfig()).build()
val builder = new AsyncHttpClientConfig.Builder(config)
val wsClient:WSClient = new NingWSClient(builder.build())
Please note that this will start up threads which will not be closed until you close the client:
wsClient.underlying[NingWSClient].close()
and you may run into memory leaks if you don't close it.
Play 2.4 makes it very easy to utilize WS in a standalone app.
The following gist provides a nice working example and the following blog post provides a nice explanation.
Here are the highlights.
Configure build.sbt
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play-ws" % "2.4.0-M2"
)
Initialize the WS client
val config = new NingAsyncHttpClientConfigBuilder(DefaultWSClientConfig()).build
val builder = new AsyncHttpClientConfig.Builder(config)
val client = new NingWSClient(builder.build)
Use WS
client.url("http://www.example.com").get
Release WS resources
client.close()
A started PlayApplication contains a client instance, which WS.client simply points to it. Since you won't start a Play application, You have to create your own client, like this:
val client = {
val builder = new com.ning.http.client.AsyncHttpClientConfig.Builder()
new play.api.libs.ws.ning.NingWSClient(builder.build())
}
client.url("http://example.com/").get()
Have a look on my project for a similar usecase, I am using play-ws and play-json, without Play itself.
I'm attempting to get Swagger working in a Play2 application. I've include the dependancy in build.sbt. "com.wordnik" %% "swagger-play2" % "1.3.1"
I've defined a series of routes.
GET /api-docs controllers.ApiHelpController.getResources
GET /api-docs/building controllers.ApiHelpController.getResource(path = "/building")
GET /building controllers.Application.building
I also have a model that pulls data from Slick and has annotations.
package models
import scala.slick.driver.SQLServerDriver.simple._
import play.api.libs.json._
import play.api.db.DB
import play.api.Play.current
import Database.threadLocalSession
#XmlRootElement(name = "Building")
case class Building(#XmlElement(name = "BuildingCode") BuildingCode: String,
#XmlElement(name = "BuildingDescription") BuildingDescription: String)
object Building {
lazy val database = Database.forDataSource(DB.getDataSource())
implicit val BuildingReads = Json.reads[Building]
implicit val BuildingWrites = Json.writes[Building]
val BuildingTable = new Table[Building]("building"){
def BuildingCode = column[String]("BuildingCode", O.PrimaryKey)
def BuildingDescription = column[String]("BuildingDescription")
def * = BuildingCode ~ BuildingDescription <> (Building.apply _, Building.unapply _)
}
def getAll: Seq[Building] = {
database withSession {
val q = Query(BuildingTable)
q.list
}
}
}
Here is what my controller looks like.
object Application extends Controller {
def building = Action {
Ok(Json.toJson(Building.getAll))
}
}
When I navigate to /api-docs the page renders.
{"apiVersion":"beta","swaggerVersion":"1.2"}
Then if I navigate to /api-docs/building nothing is rendered. Finally when I navigate to /building I receive the payload. I'm not sure what else I have to do for Swagger to generate it's data. Can someone point me in the right direction?
Can you post your controller implementation? The error is most likely due to missing/improper annotations.
Also, check out https://github.com/wordnik/swagger-core/tree/master/samples/scala-play2 for a good sample play2-swagger app.