Inject database connection pool - mysql

I have started using MacWire for the dependency injection of my Play app, and I am having problems trying to inject the database connection.
Before using DI, my code looked like this:
DB.withConnection { implicit connection =>
...
}
This is not working anymore after using DI. I get the following exception: java.lang.InstantiationException: play.api.db.DBApi.
My application loader:
class Loader extends ApplicationLoader {
def load(context: Context) = {
val components = new BuiltInComponentsFromContext(context) with Components
components.application
}
}
The main components of the app:
trait Components extends BuiltInComponents with I18nComponents
with RepositoryModule {
lazy val assets: Assets = wire[Assets]
lazy val router: Router = wire[Routes] withPrefix "/"
}
And the repository module:
trait RepositoryModule {
lazy val userRepository = wire[UserRepository]
}
How can I get and use a database connection pool and inject it so it can be used within the repository?

I solved it using the DBComponents and BoneCPComponents traits in the RepositoryModule. With them, I could get a Database object and inject it to the repositories. This is the code I'm using for the module:
trait RepositoryModule extends BuiltInComponents with DBComponents with BoneCPComponents {
lazy val database: Database = dbApi.database("default")
lazy val userRepository = wire[UserRepository]
}
The database "default" will use the db.default configurations in the application.conf. The main problem with this solution is that you need to get the connections from the pool and return them when you're done. I don't know if it can be improved to mimic the withConnection method.
An example of the user repository using the injected database:
class UserRepository(db: Database) {
def deleteAdults: Unit = {
val connection: Connection = db.getConnection()
val removed: Int = SQL("DELETE * FROM User WHERE age > 18").executeUpdate()(connection)
connection.close()
}
}

Related

Implementing a diplomatic AXI Stream interface in Chisel - BundleMap.cloneType error

I am trying to build a minimal example, of how to generate an AXI4Stream interface using Chisel and diplomacy. I am using the diplomatic interface already available in rocket-chip (freechips.rocketchip.amba.axis). I have some experience with Chisel, but I am still trying to learn diplomacy.
Anyway, I've managed to create a small APB example using the answer provided here: IP block generation/testing when using diplomacy. Possible to give dummy node?
Following that, I tried to create a similar, simple AXI Stream example, but I keep getting errors. Concretely, I get the following error:
[error] (Compile / run) java.lang.Exception: Unable to use BundleMap.cloneType on class freechips.rocketchip.amba.axis.AXISBundleBits, probably because class freechips.rocketchip.amba.axis.AXISBundleBits does not have a constructor accepting BundleFields. Consider overriding cloneType() on class freechips.rocketchip.amba.axis.AXISBundleBits
The code:
package chipyard.example
import chisel3._
import chisel3.internal.sourceinfo.SourceInfo
import chisel3.stage.ChiselStage
import freechips.rocketchip.config.{Config, Parameters}
import freechips.rocketchip.amba.axis._
import freechips.rocketchip.diplomacy.{SimpleNodeImp, ValName, SourceNode, NexusNode,
SinkNode, LazyModule, LazyModuleImp, TransferSizes,
SimpleDevice, AddressSet}
class MyAxisController(implicit p: Parameters) extends LazyModule {
val device = new SimpleDevice("my-device", Seq("tutorial,my-device0"))
val axisParams = AXISSlaveParameters.v1(name = "axisSlave", supportsSizes = TransferSizes(8,8))
val axisPortParams = AXISSlavePortParameters.v1(slaves = Seq(axisParams))
val node = AXISSlaveNode(portParams = Seq(axisPortParams))
lazy val module = new LazyModuleImp(this) {
val ins = node.in.unzip._1
val register = RegInit(UInt(8.W), 0.U)
register := register + ins(0).bits.data
}
}
class AXISMaster()(implicit p: Parameters) extends LazyModule {
val axisMasterParams = AXISMasterParameters.v1(
name = "axisMaster", emitsSizes = TransferSizes(8, 8)
)
val axisMasterPortParams = AXISMasterPortParameters.v1(
masters = Seq(axisMasterParams),
beatBytes = Option(8)
)
val node = AXISMasterNode(
portParams = Seq(axisMasterPortParams)
)
lazy val module = new LazyModuleImp(this) {
//The dontTouch here preserves the interface so logic is generated
dontTouch(node.out.head._1)
}
}
class MyAxisWrapper()(implicit p: Parameters) extends LazyModule {
val master = LazyModule(new AXISMaster)
val slave = LazyModule(new MyAxisController()(Parameters.empty))
slave.node := master.node
lazy val module = new LazyModuleImp(this) {
//nothing???
}
}
and Main.scala:
package chipyard.example
import chisel3._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import java.io.File
import java.io.FileWriter
/**
* An object extending App to generate the Verilog code.
*/
object Main {
def main(args: Array[String]): Unit = {
//(new chisel3.stage.ChiselStage).execute(args, Seq(ChiselGeneratorAnnotation(() => LazyModule(new MyWrapper()(Parameters.empty)).module)))
val verilog = (new chisel3.stage.ChiselStage).emitVerilog(
LazyModule(new MyAxisWrapper()(Parameters.empty)).module
)
//println(s"```verilog\n$verilog```")
val fileWriter = new FileWriter(new File("./gen/gen.v"))
fileWriter.write(verilog)
fileWriter.close()
}
}
The code is also available at https://github.com/jurevreca12/temp_dspblock_example/tree/axistream2/scala/main.
My question is. Why do I get this error? Or am I doing something wrong in the first place, and is there an easier way to create an AXIStream module?
I appreciate any feedback.
This looks to be an issue with Rocket-Chip's changes to bump to Chisel 3.5. During those changes, AXISBundleBits had its cloneType removed even though it extends off BundleMap (and therefore requires cloneType due to extending off Record).
I don't have all the details of cloneType at this time, but essentially:
Records require cloneType
Bundles used to require cloneType, but since the compiler plugin was implemented, as of 3.5 they no longer require cloneType.
BundleMap is a confusing case because it is a custom Bundle type extending directly off Record and isn't of type Bundle. Therefore, it shouldn't have had its cloneType method removed during the 3.5 Chisel bump and that will need to be added back for AXIS in RC's main branch to start working again.
Edit: the cloneType exception issue is now fixed for 3.5 on the main branch :)

play 2.5 DB issue - Use dependency injection

Issue:
I am facing the below issue in play 2.5 while compilation.
You do not have an implicit Application in scope. If you want to
bring the current running Application into context, please use
dependency injection.
Getting issue in line - DB.withConnection {^
Code snippet:
object User {
def getId(emailid: String): Option[Int] = {
DB.withConnection { implicit c =>
SQL("select id from user where email = {email}").on(
'email -> emailid).as(SqlParser.scalar[Int].singleOpt)
}
}
}
How do I fix the issue?
Make User a class and inject it where you need it.
class User #Inject() (db: Database) { ..}
And in your controller:
class MyController #Inject() (user: User) extends Controller {
// ..
user.getId
// ..
}
Read more here: https://www.playframework.com/documentation/2.5.x/ScalaDatabase
I think the problem you met is like this:
You do not have an implicit Application in scope: PlayFramework with Oracle
have a try that import the package of 'play.api.Play.current', namely add the following in your code file
import play.api.Play.current
have a good luck

How to insert json fixture data in Play Specification tests?

I have a Scala Play 2.2.2 application and as part of my Specification tests I would like to insert some fixture data for testing preferably in json format. For the tests I use the usual in-memory H2 database. How can I accomplish this? I have searched all the documentation but there is no mention to this anywhere.
Note that I would prefer not to build my own flavor of fixture implementation via the Global. There should be a non-hacky way to this right?
AFAIK there is no built-in stuff to do this, ala Rails, and it's hard to imagine what the devs could do without making Play Scala much more opinionated about the way persistence should be handled (which I'd personally consider a negative.)
I also use H2 for testing and employ plain SQL fixtures in a resource file and load them before tests using a couple of (fairly simple) helpers:
package object helpers {
import java.io.File
import java.sql.CallableStatement
import org.specs2.execute.{Result, AsResult}
import org.specs2.mutable.Around
import org.specs2.specification.Scope
import play.api.db.DB
import play.api.test.FakeApplication
import play.api.test.Helpers._
/**
* Load a file containing SQL statements into the DB.
*/
private def loadSqlResource(resource: String)(implicit app: FakeApplication) = DB.withConnection { conn =>
val file = new File(getClass.getClassLoader.getResource(resource).toURI)
val path = file.getAbsolutePath
val statement: CallableStatement = conn.prepareCall(s"RUNSCRIPT FROM '$path'")
statement.execute()
conn.commit()
}
/**
* Run a spec after loading the given resource name as SQL fixtures.
*/
abstract class WithSqlFixtures(val resource: String, val app: FakeApplication = FakeApplication()) extends Around with Scope {
implicit def implicitApp = app
override def around[T: AsResult](t: => T): Result = {
running(app) {
loadSqlResource(resource)
AsResult.effectively(t)
}
}
}
}
Then, in your actual spec you can do something like so:
package models
import helpers.WithSqlFixtures
import play.api.test.PlaySpecification
class MyModelSpec extends PlaySpecification {
"My model" should {
"locate items correctly" in new WithSqlFixtures("model-fixtures.sql") {
MyModel.findAll().size must beGreaterThan(0)
}
}
}
Note: this specs2 stuff could probably be better.
Obviously if you really need JSON you'll have to add extra machinery to deserialise your models and persist them in the database (often in your app you'll be doing these things anyway, in which case that might be relatively trivial.)
You'll also need:
Some evolutions to establish your DB schema in conf/evolutions/default
The evolution plugin enabled, which will build your schema when the FakeApplication starts up
The appropriate H2 DB config

Problems with Scala Play Framework Slick Session

I'm creating an application in Scala using Play 2.2. I'm using play-slick 0.5.0.8 as my MySQL DB connector. I have the following application controller:
package controllers
import models._
import models.database._
import play.api._
import play.api.mvc._
import play.api.Play.current
import play.api.db.slick._
object Application extends Controller {
// WORKS:
def test = DBAction {
implicit session => Ok(views.html.test(Cameras.findById(1)))
}
// DOES NOT WORK:
def photo = Action {
val p = PhotoFetcher.fetchRandomDisplayPhoto(someParametersBlah))
Ok(views.html.photo(p))
}
}
As you can see, the test DBAction works, and it's able to fetch a photo from the DB just fine. Unfortunately, the photo Action does not work.
My PhotoFetcher.fetchRandomDisplayPhoto(blah) does a bunch of different things. Buried inside of it is a call to Cameras.findById(blah), which should return a Camera object (which works in the test DBAction). However, with this configuration I get the following error:
could not find implicit value for parameter s: slick.driver.MySQLDriver.simple.Session
I have tried making the photo Action into a DBAction, like so:
def photo = DBAction {
implicit session => {
val p = PhotoFetcher.fetchRandomDisplayPhoto(someParametersBlah))
Ok(views.html.photo(p))
}
}
But that just results in the same missing session error. It's like PhotoFetcher doesn't know about the implicit session.
The other thing I've tried is importing slick.session.Database.threadLocalSession in my PhotoFetcher, but that only results in the following error:
SQLException: No implicit session available; threadLocalSession can only be used within a withSession block
If it's any help, this is a simplified version of my Cameras object:
package models.database
import models.Format.Format
import scala.slick.driver.MySQLDriver.simple._
case class Camera(id: Long,
otherStuff: String)
trait CamerasComponent {
val Cameras: Cameras
class Cameras extends Table[Camera]("cameras") {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def otherStuff = column[String]("otherStuff", O.NotNull)
def * = id ~ otherStuff <> (Camera.apply _, Camera.unapply _)
val byId = createFinderBy(_.id)
val byOtherStuff = createFinderBy(_.otherStuff)
}
}
object Cameras extends DAO {
def insert(camera: Camera)(implicit s: Session) { Cameras.insert(camera) }
def findById(id: Long)(implicit s: Session): Option[Camera] = Cameras.byId(id).firstOption
def findByOtherStuff(otherStuff: String)(implicit s: Session): Option[Camera] = Cameras.byOtherStuff(model).firstOption
}
So, it seems as if I've gotten crossed-up somewhere. Right now it's only possible for me to access my DAO objects directly from a Controller DBAction, and not from inside of some different class. Any help would be appreciated. Thanks!
Does your definition of PhotoFetcher.fetchRandomDisplayPhoto.fetchRandomDisplayPhoto take an implicit session?
// PhotoFetcher
def fetchRandomDisplayPhoto(args: Blah*)(implicit s: Session) = {
// ...
val maybeCam = Cameras.findById(blah) // <- sees the implicit session
// ...
}
Or are you relying on a threadLocalsession in PhotoFetcher? (no implicit session argument for fetchRandomDisplayPhoto)?
While Slick's threadLocalSession is handy for quickly trying out stuff, it can lead to confusion and loss of clarity later on. It's best to just use explicit (implicit s: Session) parameter lists for all methods that call your Slick models. This also plays
well with DBAction, letting the framework manage sessions.
The downside is you have to have (implicit s: Session) on all your methods - there
are workarounds like this:
https://github.com/freekh/play-slick/issues/20
Scala isn't verbose and is very amenable to refactoring - so I'd recommend thinking
about crossing that bridge when you come to it, and use DBAction for all actions
that do database stuff; give all methods that call your database models an
implicit session, and see how much that mileage that gives you.

Are Akka .conf dispatcher configuration working?

I'm using Akka 2.2-RC1 and I'm not able to get Akka to load dispatcher configuration from application.conf:
my-dispatcher {
type = PinnedDispatcher
executor = "thread-pool-executor"
}
akka.actor.deployment {
/test {
dispatcher = my-dispatcher
}
}
When instantiated from code like
val test = system.actorOf(Props[Test], "test")
by logs it is still using akka.actor.default-dispatcher.
When I'm adding .withDispatcher("my-dispatcher") to Props all is working properly and my-dispatcher is used. But I do not like idea of adding .withDispatcher(...) to all my actors...
Do anyone know where could be a problem? I was thinking that actor path may be wrong, but apllication.conf routing configuration works properly (with exception of custom routee dispatcher, again).
After some testing I've found that this effect is caused by use of RemoteActorRefProvider. As soon as I disabled it and changed to default
akka.actor.provider = "akka.actor.LocalActorRefProvider"
dispatchers were configuring from config properly.
I guess with remoting enabled Akka looks elsewhere for configuration of actor dispatchers or maybe remote refs have different logical paths?
This worked fine for me on the same version of akka that you were using. My config:
test{
my-dispatcher {
type = PinnedDispatcher
executor = "thread-pool-executor"
}
akka.actor.deployment {
/test-actor {
dispatcher = my-dispatcher
}
}
}
My code:
object ActorTest{
def main(args: Array[String]) {
val conf = ConfigFactory.load()
val system = ActorSystem("test", conf.getConfig("test"))
val ref = system.actorOf(Props[TestActor], "test-actor")
}
}
class TestActor extends Actor{
def receive = {
case _ =>
}
}
I used jconsole and shows that the pinned dispatcher was listed under the Threads tab