How do I load configuration file on startup - scala

I have application.conf file for my Scala program in main/resources. I load the configuration file using Config.load(). It is all working. But my config loading code is inside my service class. I want something like when program starts then first thing it doing is loading configuration. Then I want to use DI to pass this around.
This is easy in Scala Play because I just write Module class and specify in config file. Play then loads my config at start up. But how can I do this with non-Play project - just plain scala program.

Play uses Guice out-of-the-box for dependency injection, so you could consider using the same.
Here is an example of how guice can be used to inject configuration into services:
package example
import com.google.inject.{AbstractModule, Guice, Inject, Injector, Provides, Singleton}
import com.typesafe.config.ConfigFactory
import scala.jdk.CollectionConverters._
case class Config(foo: String, bar: String)
class Module extends AbstractModule {
#Provides
#Singleton
def getConfig: Config = {
val conf = ConfigFactory.load()
Config(
conf.getString("foo"),
conf.getString("bar")
)
}
}
class QuxService #Inject()(config: Config) {
println(config)
}
object ConfigInjectionExample extends App {
val injector: Injector = Guice.createInjector(List(new Module).asJava)
injector.getInstance(classOf[QuxService])
}
which outputs
Config(hello,world)
given the following resources/application.conf
foo="hello"
bar="world"
and the following dependencies
libraryDependencies += "net.codingwell" %% "scala-guice" % "4.2.6",
libraryDependencies += "com.typesafe" % "config" % "1.3.4"

Related

object evolutions is not a member of package play.api.db.slick

I'm a newbie to Play framework and can't figure out why I'm getting this error in my application loader class that I copied and pasted from the Play 2.6 documention here with some modifications for new versions of slick and slick-evolutions.
Here is the part of my build.sbt that references the libraries:
scalaVersion := "2.12.2"
libraryDependencies ++= Seq(evolutions, jdbc)
libraryDependencies ++= Seq(jdbc, ehcache , ws , specs2 % Test , guice )
libraryDependencies ++= Seq("com.typesafe.play" %% "play" % "2.6.11")
libraryDependencies += "com.typesafe.play" %% "play-slick" % "3.0.1"
libraryDependencies += "com.typesafe.play" %% "play-slick-evolutions" % "3.0.1"
libraryDependencies ++= Seq("mysql" % "mysql-connector-java" % "5.1.36")
Here is my application.conf
play.application.loader=AppComponents
And here is the AppComponents class which I put in my root directory
import play.api.ApplicationLoader.Context
import play.api.BuiltInComponentsFromContext
import play.api.db.{Database, DBComponents, HikariCPComponents}
import play.api.db.slick.evolutions.{SlickEvolutionsComponents}
import play.api.routing.Router
import play.filters.HttpFiltersComponents
class AppComponents(cntx: Context)
extends BuiltInComponentsFromContext(cntx)
with DBComponents
with SlickEvolutionsComponents
with HikariCPComponents
with HttpFiltersComponents
{
// this will actually run the database migrations on startup
applicationEvolutions
}
I've examined the play-slick-evolutions_2.12-3.0.1.jar jar that was downloaded and it indeed has has play.api.db.slick.evolutions there. I've also tried earlier versions that comport exactly with the code in the Play 2.6 documentation, but there too, evolutions is not a member of the package.
First, a project rebuild took care of the initial error, but it did not solve the problem with the Application Loader. To fix this I returned to the Play 2.6 documentation and restored the class to the segment they provided and removed the play-slick sbt entries, restoring to the entries in the documentation. There was still a problem, and on finding another example it became evident that I didn't have a complete class. Here it is:
import play.api.ApplicationLoader
import play.api.ApplicationLoader.Context
import play.api.BuiltInComponentsFromContext
import play.api.db.{Database, DBComponents, HikariCPComponents}
import play.api.db.evolutions.EvolutionsComponents
import play.api.routing.Router
import play.filters.HttpFiltersComponents
class MyApplicationLoader extends ApplicationLoader {
def load(context: Context) = {
new MyComponents(context).application
}
}
class MyComponents(cntx: Context)
extends BuiltInComponentsFromContext(cntx)
with DBComponents
with EvolutionsComponents
with HikariCPComponents
with HttpFiltersComponents
{
// this will actually run the database migrations on startup
lazy val router = Router.empty
applicationEvolutions
}
I also adjusted my application.conf setting to:
play.application.loader=MyApplicationLoader
Note that I still need to add the routing because the lazy val router = Route.empty gives a web page that says:
Action Not Found
For request 'GET /'
These routes have been tried, in this order:

How do I set up a MySql Connection in Play 2.6 for Scala

I'm a newbie at this, and try as I might I am unable to find a full example of how to configure a Scala Play 2.6 application. There are obvious difference between versions of Play and the 2.6 documentaion doesn't have a full example.
My current state is I'm getting a ataSource or dataSourceClassName or jdbcUrl is required. error.
Also, can someone explain the purpose of the two "db" sections in application.conf,
play.db{} vs. db{}
When you use Slickyou can config it like this:
slick {
dbs {
default {
profile = "slick.jdbc.MySQLProfile$"
db {
driver = "com.mysql.jdbc.Driver"
url = "jdbc:mysql://url:3306/dbname"
user = "user"
password = "password"
// comment out for Production
connectionPool = disabled
}
}
}
}
If you're using evolutions then you have to add following line to your config:
play.evolutions.enabled = true
The evolution .sql-files for your default DB config need to be placed in
conf/evolutions/default/
A Class with some DB stuff needs following imports and injections:
import javax.inject.{Inject, Singleton}
import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider}
import slick.jdbc.JdbcProfile
#Singleton
class DBClass #Inject()(protected val dbConfigProvider: DatabaseConfigProvider)
extends HasDatabaseConfigProvider[JdbcProfile] {
import profile.api._
...
}
A Controller would look similar:
import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider}
import play.api.mvc.{AbstractController, ControllerComponents}
import slick.jdbc.{JdbcProfile, TransactionIsolation}
#Singleton
class DBController #Inject()(protected val dbConfigProvider: DatabaseConfigProvider,
cc: ControllerComponents)
extends AbstractController(cc) with HasDatabaseConfigProvider[JdbcProfile] {
import profile.api._
...
}
For implicit Execution Context you would need to this import:
import scala.concurrent.ExecutionContext.Implicits.global
For further reading of slick check this book out:
https://books.underscore.io/essential-slick/essential-slick-3.pdf
After a lot of trial and error, the following isn't throwing any exceptions:
In build.sbt
libraryDependencies ++= Seq(jdbc, ehcache , ws , specs2 % Test , guice )
libraryDependencies ++= Seq("com.typesafe.play" %% "play" % "2.6.11")
libraryDependencies += "com.typesafe.play" %% "play-slick" % "3.0.0"
libraryDependencies ++= Seq("mysql" % "mysql-connector-java" % "5.1.36")
In application.conf
db.default.driver = com.mysql.jdbc.Driver
db.default.url = "jdbc:mysql://localhost/my_database"
db.default.username = "my_user_name"
db.default.password = "my_password"
play.db {
# The combination of these two settings results in "db.default" as the
# default JDBC pool:
#config = "db"
#default = "default"
# Play uses HikariCP as the default connection pool. You can override
# settings by changing the prototype:
prototype {
# Sets a fixed JDBC connection pool size of 50
#hikaricp.minimumIdle = 50
#hikaricp.maximumPoolSize = 50
}
}

Play 2.6 evolutions DB change not applied

My project was recently updated from Play 2.5 to 2.6.13.
I added a new script 16.sql but the change were not applied in the table play_evolutions
According to the documentation 2.6, the EvolutionsComponents have to be injected if you use compile time DI. But Guice is runtime DI, so I should not have to inject any components.
I enabled the evolutions in the build.sbt
libraryDependencies ++= Seq(evolutions, jdbc)
In application.conf
play.evolutions.enabled=true
play.evolutions.autoApply=true
What is my project missing ? Any git examples are welcome
I solved it by following the documentation since upgrading to Play 2.6
Here is my code
import play.api.ApplicationLoader.Context
import play.api.{Application, ApplicationLoader, BuiltInComponentsFromContext}
import play.api.db.{DBComponents, HikariCPComponents}
import play.api.db.evolutions.EvolutionsComponents
import play.api.routing.Router
import play.filters.HttpFiltersComponents
import router.Routes
class MyApplicationLoader extends ApplicationLoader {
def load(context: ApplicationLoader.Context): Application = {
new AppComponents(context).application
}
}
class AppComponents(context: Context)
extends BuiltInComponentsFromContext(context)
with DBComponents
with EvolutionsComponents
with HikariCPComponents
with HttpFiltersComponents {
// this will actually run the database migrations on startup
applicationEvolutions
// val prefix: String = "/"
lazy val router = Router.empty
// lazy val router: Router = bind(classOf[Routes]).to(classOf[Routes])
}
And in the conf/application.conf, add this line
play.application.loader=MyApplicationLoader

unable to use WS.url() in Play app tutorial

I am doing a tutorial for Play framework with Scala. I am quite early into the tutorial and i am having a problem with ws. In my class WS is not recognized although that says to use WS.url("url-here") and to import play.api.libs._ which i have done both. I have also tried using ws.url("url-here") as well... and here wsis recognized but after that i get a "can't resolve symbol 'url'". Here is my build.sbt:
name := """play_hello"""
organization := "x.x"
version := "1.0-SNAPSHOT"
lazy val root = (project in file(".")).enablePlugins(PlayScala)
scalaVersion := "2.12.3"
libraryDependencies ++= Seq(
"org.scalatestplus.play" %% "scalatestplus-play" % "3.1.2" % Test,
"com.ning" % "async-http-client" % "1.9.29",
guice,
ws
)
And here is the code for my class:
package controllers
import javax.inject.Inject
import com.ning.http.client.oauth.{ConsumerKey, RequestToken}
import play.api.Play.current
import play.api.libs._
import play.api.mvc._
import scala.concurrent.Future
class Application #Inject()(cc: ControllerComponents) extends
AbstractController(cc){
def tweets = Action.async{
credentials.map { case (consumerKey, requestToken) =>
WS.url("http://stream.twitter.com")
Future.successful{
Ok
}
}getOrElse{
Future.successful{
InternalServerError("Twitter credentials are missing!")
}
}
}
def credentials: Option[(ConsumerKey, RequestToken)] = for{
apiKey <- current.configuration.getString("twitter.apiKey")
apiSecret <- current.configuration.getString("twitter.apiSecret")
token <- current.configuration.getString("twitter.token")
tokenSecret <- current.configuration.getString("twitter.tokenSecret")
}yield (
new ConsumerKey(apiKey, apiSecret),
new RequestToken(token, tokenSecret)
)
}
I Figure that most likely this is some type of problem with a dependency conflict. Here is a screenshot of ws related libraries in project structure. I would appreciate any help in finding a solution to this. Thank you.
The solution was to add ws: WSClient to the parameters of Application class constructor. Apperently standalone WS object has been removed in more recent versions of ws library.
class Application #Inject()(cc: ControllerComponents, ws: WSClient) extends AbstractController(cc)
Now i can use:
ws.url("https://stream.twitter.com/1.1/statuses/filter.json")
Also according to the documentation on play website if you for some reason can not use an injected WSClient, then you can create an instance of one and use that.

How to make Squeryl work with the Play! Framework?

I'm trying to learn how to make a simple database app with Play and Squeryl. I've made the Tasks app from the Play tutorial, but I want to change the model / schema so that it uses Squeryl instead of Anorm. I've been looking at different tutorials, examples and answers, but I haven't really figured out how to do this.
So, given the source code from the Play Tutorial (ScalaTodoList); how do I proceed to make it work with Squeryl?
More specifically:
How do I implement the all(), create(), and delete() methods in my model? (I'd like to use auto-incrementing ID's for the Tasks)
Which database adapter to use is currently hard coded in Build.scala and Global.scala (see below). How can I make it such that it automatically uses H2 for dev/testing and Postgres on Heroku, like it does for Anorm in the Play tutorial?
How do I make sure that it automatically creates my tables?
This is what I've done thus far
I've completed the Play ScalaTodoList Tutorial.
In project/Build.scala, object ApplicationBuild, I've added the dependencies:
// From the "Squeryl Getting Started tutorial"
val posgresDriver = "postgresql" % "postgresql" % "8.4-702.jdbc4"
val h2 = "com.h2database" % "h2" % "1.2.127"
// From the "Squeryl Getting Started tutorial"
libraryDependencies ++= Seq(
"org.squeryl" %% "squeryl" % "0.9.5",
h2
)
// From the Play tutorial
val appDependencies = Seq(
// Add your project dependencies here,
"org.squeryl" %% "squeryl" % "0.9.5", // Copied from above so that it compiles (?)
"postgresql" % "postgresql" % "8.4-702.jdbc4"
)
added app/Global.scala (taken from the SO answer mentioned above, just changed the adapter to H2):
import play.db.DB
import play.api.Application
import play.api.GlobalSettings
import org.squeryl._
import org.squeryl.adapters._
object Global extends GlobalSettings {
override def onStart(app: Application): Unit =
{
SessionFactory.concreteFactory = Some(
() => Session.create(DB.getDataSource().getConnection(),
dbAdapter));
}
override def onStop(app: Application): Unit =
{
}
val dbAdapter = new H2Adapter(); // Hard coded. Not good.
}
in app/models/Task.scala I've added imports and removed the Anorm implemetations in all(), create(), and delete().
The controller from the Play tutorial expects the all() method to return List[Task].
import org.squeryl.PrimitiveTypeMode._
import org.squeryl.Schema
import org.squeryl.annotations.Column
case class Task(id: Long, label: String)
object Task extends Schema {
val tasks = table[Task] // Inspired by Squeryl tutorial
def all(): List[Task] = {
List[Task]() // ??
}
def create(label: String) {
// ??
}
def delete(id: Long) {
// ??
}
}
The rest of the files are left as they were at the end of the Play tutorial.
Here is an example Play 2 project with Squeryl:
https://github.com/jamesward/play2bars/tree/scala-squeryl
The "Play for Scala" (MEAP) book has a chapter on Squeryl integration
http://www.manning.com/hilton/