scala Play Framework 2.4: sending email - scala

I trying to send an email from scala Play framework 2.4 while using play-mailer, I have followed the instruction from their sample page but with no success.
I have added the dependency to build.sbt:
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play-mailer" % "3.0.1"
)
In application.conf the I have added the following:
play.mailer {
host=smtp.gmail.com
port=465
ssl=true
tls=true
user="testme#gmail.com"
password=abracadabra
}
And finally, the Mailing Class:
package controllers
import java.io.File
import javax.inject.Inject
import org.apache.commons.mail.EmailAttachment
import play.api.Configuration
import play.api.Play.current
import play.api.libs.mailer._
class Mail(mailer: MailerClient) {
def send = {
val cid = "1234"
val email = Email(
"Simple email",
"Mister FROM <from#email.com>",
Seq("Miss TO <to#email.com>"),
bodyText = Some("A text message"),
bodyHtml = Some("some data....")
)
mailer.send(email)
}
}
So far without compilation errors, however I don't understand how to initialize this class.. how should I get the "MailerClient" instance?
In the documentation it is written "Then in your router definition, use the trait MailerComponents", with the following code example:
import play.api._
import play.api.ApplicationLoader.Context
import router.Routes
import play.api.libs.mailer._
class MyApplicationLoader extends ApplicationLoader {
def load(context: Context) = {
new ApplicationComponents(context).application
}
}
class ApplicationComponents(context: Context) extends BuiltInComponentsFromContext(context) with MailerComponents {
lazy val myComponent = new MyComponent(mailerClient)
// create your controllers here ...
lazy val router = new Routes(...) // inject your controllers here
}
(I have added "play.application.loader=SimpleApplicationLoader" in application.conf)
but I get the following compilation errors:
D:\myApp\app\SimpleApplicationLoader.scala:12: not found: type MailerComponents
[error] class ApplicationComponents(context: Context) extends BuiltInComponentsFromContext(context) with MailerComponents {
[error] ^
[error] D:\myApp\app\SimpleApplicationLoader.scala:13: not found: value mailerClient
[error] lazy val applicationController = new controllers.Mail(mailerClient)
[error] ^
[error] two errors found
[error] (compile:compileIncremental) Compilation failed
Any ideas?

You can go with the run-time dependency injection, as the other answer has suggested. But if you want to go with your current approach, read on...
The problem is, the MailerComponents trait doesn't exist in the 3.x branch. it does seem to exist in the master branch, but not in their next branch. I am not sure what they are doing there.
If you want to continue with the example, you'll need to do a bit of fiddling and figure out how to make it compile. For ex. with a bit of looking around, I came up with the following.
import play.api._
import play.api.ApplicationLoader.Context
import router.Routes
import play.api.libs.mailer._
class SimpleApplicationLoader extends ApplicationLoader {
def load(context: Context) = {
new ApplicationComponents(context).application
}
}
class ApplicationComponents(context: Context) extends BuiltInComponentsFromContext(context) {
val mailerClient = new CommonsMailer(configuration)
lazy val applicationController = new controllers.ApplicationScala(mailerClient)
lazy val assets = new controllers.Assets(httpErrorHandler)
lazy val router = new Routes(httpErrorHandler, applicationController)
}
Basically, instead of relying on the non-existent MailerComponent to create a mailerClient for me, I just did it myself.
If you have the following line in controllers.ApplicationScala
val id = mailer.configure(Configuration.from(Map("host" -> "typesafe.org", "port" -> 1234))).send(email)
Replace it with:
val id = mailer.send(email)
And it will compile. Meanwhile, I think I should raise an issue on github about this. And maybe you should.

I believe you could simply let play framework inject the mail client. Setting up the configuration and annotating your constructor with #Inject() should work.
Declaration of your Mail controller would look like this:
class Mail #Inject() (mailer: MailerClient) {

Related

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

Play Framework 2.5 Test ApplicationLifecycle Guice Specs2 setup

I am trying to run some functional tests with play2-reactivemongo. I will try to be as concrete as possible, but if something is missing please let me know.
My dependencies are here
libraryDependencies ++= Seq(
cache,
"org.reactivemongo" %% "play2-reactivemongo" % "0.12.0",
"com.mohiva" %% "play-silhouette" % "4.0.0",
"com.mohiva" %% "play-silhouette-testkit" % "4.0.0" % "test",
specs2 % Test
)
In MongoUserDao.scala
import play.modules.reactivemongo._
import play.modules.reactivemongo.json._
import reactivemongo.play.json.collection.JSONCollection
class MongoUserDao #Inject() (val reactiveMongoApi: ReactiveMongoApi) extends UserDao {
val usersFuture = reactiveMongoApi.database.map(_.collection[JSONCollection]("users"))
...
}
In DaoSpecResources.scala
trait DaoSpecResources {
val timeout = DurationInt(10).seconds
val fakeApp = new GuiceApplicationBuilder()
.in(Mode.Test)
.configure(
"play.modules.enabled" -> List("play.modules.reactivemongo.ReactiveMongoModule"),
"mongodb.uri" -> "mongodb://localhost:27017/test"
)
.build
val reactiveMongoApi = fakeApp.injector.instanceOf[ReactiveMongoApi]
...
}
When I try to run the test I get this error
[error] cannot create an instance for class daos.UserDaoSpec
[error] caused by com.google.inject.CreationException: Unable to create injector, see the following errors:
[error]
[error] 1) No implementation for play.api.inject.ApplicationLifecycle was bound.
[error] while locating play.api.inject.ApplicationLifecycle
[error] for parameter 1 at services.ApplicationTimer.<init>(ApplicationTimer.scala:24)
[error] at Module.configure(Module.scala:23) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)
[error]
[error] 1 error
This is caused by app/services/ApplicationTimer.scala, which depends on ApplicationLifecycle, but you haven't bound any implementation to ApplicationLifecycle. ApplicationTimer is a demo included in every new Play project. You should probably remove it completely if you don't need it, otherwise at least disable it if running in test mode. See disabling modules and overriding modules.
Solution
However, since DefaultReactiveMongoApi also depends on ApplicationLifecycle, you'll need to provide a binding to an implementation of ApplicationLifecycle. The easiest way:
import play.api.inject.{ ApplicationLifecycle, DefaultApplicationLifecycle }
import play.api.inject.bind
trait DaoSpecResources {
val timeout = DurationInt(10).seconds
val fakeApp = new GuiceApplicationBuilder()
.in(Mode.Test)
.configure(
"play.modules.enabled" -> List("play.modules.reactivemongo.ReactiveMongoModule"),
"mongodb.uri" -> "mongodb://localhost:27017/test"
)
.bindings(bind[ApplicationLifecycle].to[DefaultApplicationLifecycle])
.build
val reactiveMongoApi = fakeApp.injector.instanceOf[ReactiveMongoApi]
val lifecycle = fakeApp.injector.instanceOf[DefaultApplicationLifecycle]
def stopApp = lifecycle.stop()
}
(added 5 lines: imports, bindings, lifecycle and stopApp)
Then, in your test spec, add step(stopApp) at the end, like so:
class FooSpec extends PlaySpecification with DaoSpecResources {
// Your examples...
step(stopApp)
}
Alternative solution
Personally, I'd create a specialized trait extending Specification or PlaySpecification which would set up and tear down everything automatically, like in this example from specs2 documentation.
trait PlayWithMongoSpecification extends PlaySpecification {
val timeout = DurationInt(10).seconds
val fakeApp = new GuiceApplicationBuilder()
.in(Mode.Test)
.configure(
"play.modules.enabled" -> List("play.modules.reactivemongo.ReactiveMongoModule"),
"mongodb.uri" -> "mongodb://localhost:27017/test"
)
.bindings(bind[ApplicationLifecycle].to[DefaultApplicationLifecycle])
.build
val reactiveMongoApi = fakeApp.injector.instanceOf[ReactiveMongoApi]
val lifecycle = fakeApp.injector.instanceOf[DefaultApplicationLifecycle]
def stopApp = lifecycle.stop()
override def map(fs: =>Fragments) = fs ^ step(stopApp)
}
class FooSpec extends PlayWithMongoSpecification {
// Your examples...
}
You may consider making reactiveMongoApi a lazy val.

Cannot import class router.Routes in ApplicationLoader on Play 2.5

I'm having a problem with a migration to Play 2.5 with Scala. I had to start using DependencyInjection and after reading all the Play Framework 2.5 migration documentation and making all the corresponding implementations I arrived to an strange problem. Play indicates that class Routes should be automatically generated with the new DependencyInjection schema but when I tried to import the class in my custom ApplicationLoader, the compiler tells me that cannot resolve symbol "router". Below is part of my code, hope you can help me with this, thanks!
import controllers.Assets
import controllers.api.clients.ClientsController
import play.api.ApplicationLoader.Context
import play.api._
import play.api.libs.ws.ahc.AhcWSComponents
import router.Routes
class AppLoader extends ApplicationLoader {
def load(context: Context) = {
LoggerConfigurator(context.environment.classLoader).foreach {
_.configure(context.environment)
}
new AppComponents(context).application
}
}
class AppComponents(context: Context) extends BuiltInComponentsFromContext(context) with AhcWSComponents {
lazy val clientsController: ClientsController = new ClientsController(wsClient)
lazy val assets: Assets = new Assets(httpErrorHandler)
lazy val router = new Routes(
httpErrorHandler,
clientsController,
assets
)
}
Check the following:
Make sure your build.sbt contains routesGenerator := InjectedRoutesGenerator
Execute playCompileEverything in sbt and refresh your project in your IDE

Specs2: how to test a class with more than one injected dependency?

Play 2.4 app, using dependency injection for service classes.
I found that Specs2 chokes when a service class being tested has more than one injected dependency. It fails with "Can't find a constructor for class ..."
$ test-only services.ReportServiceSpec
[error] Can't find a constructor for class services.ReportService
[error] Error: Total 1, Failed 0, Errors 1, Passed 0
[error] Error during tests:
[error] services.ReportServiceSpec
[error] (test:testOnly) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 2 s, completed Dec 8, 2015 5:24:34 PM
Production code, stripped to bare minimum to reproduce this problem:
package services
import javax.inject.Inject
class ReportService #Inject()(userService: UserService, supportService: SupportService) {
// ...
}
class UserService {
// ...
}
class SupportService {
// ...
}
Test code:
package services
import javax.inject.Inject
import org.specs2.mutable.Specification
class ReportServiceSpec #Inject()(service: ReportService) extends Specification {
"ReportService" should {
"Work" in {
1 mustEqual 1
}
}
}
If I remove either UserService or SupportService dependency from ReportService, the test works. But obviously the dependencies are in the production code for a reason. Question is, how do I make this test work?
Edit: When trying to run the test inside IntelliJ IDEA, the same thing fails, but with different messages: "Test framework quit unexpectedly", "This looks like a specs2 exception..."; see full output with stacktrace. I opened a Specs2 issue as instructed in the output, though I have no idea if the problem is in Play or Specs2 or somewhere else.
My library dependencies below. (I tried specifying Specs2 version explicitly, but that didn't help. Looks like I need specs2 % Test as is, for Play's test classes like WithApplication to work.)
resolvers += "scalaz-bintray" at "https://dl.bintray.com/scalaz/releases"
libraryDependencies ++= Seq(
specs2 % Test,
jdbc,
evolutions,
filters,
"com.typesafe.play" %% "anorm" % "2.4.0",
"org.postgresql" % "postgresql" % "9.4-1205-jdbc42"
)
There is limited support for dependency injection in specs2, mostly for execution environments or command-line arguments.
There is nothing preventing you from just using a lazy val and your favourite injection framework:
class MySpec extends Specification with Inject {
lazy val reportService = inject[ReportService]
...
}
With Play and Guice, you could have a test helper such as this:
import play.api.inject.guice.GuiceApplicationBuilder
import scala.reflect.ClassTag
trait Inject {
lazy val injector = (new GuiceApplicationBuilder).injector()
def inject[T : ClassTag]: T = injector.instanceOf[T]
}
If you really need runtime dependency injection, then it's better to use Guice loading, I guess:
package services
import org.specs2.mutable.Specification
import scala.reflect.ClassTag
import com.google.inject.Guice
// Something you'd like to share between your tests
// or maybe not
object Inject {
lazy val injector = Guice.createInjector()
def apply[T <: AnyRef](implicit m: ClassTag[T]): T =
injector.getInstance(m.runtimeClass).asInstanceOf[T]
}
class ReportServiceSpec extends Specification {
lazy val reportService: ReportService = Inject[ReportService]
"ReportService" should {
"Work" in {
reportService.foo mustEqual 2
}
}
}
Alternatively you can implement Inject object as
import scala.reflect.ClassTag
import play.api.inject.guice.GuiceApplicationBuilder
object Inject {
lazy val injector = (new GuiceApplicationBuilder).injector()
def apply[T : ClassTag]: T = injector.instanceOf[T]
}
It depends whether you want to use Guice directly, or thru play wrappers.
Looks like you are out of luck ATM: The comment says
Try to create an instance of a given class by using whatever constructor is available and trying to instantiate the first parameter recursively if there is a parameter for that constructor.
val constructors = klass.getDeclaredConstructors.toList.filter(_.getParameterTypes.size <= 1).sortBy(_.getParameterTypes.size)
i.e. Specs2 doesn't provide own DI out-of-the box,
Or you can reimplement the functionality yourself, if Guice isn't working for you.
App code:
package services
import javax.inject.Inject
class ReportService #Inject()(userService: UserService, supportService: SupportService) {
val foo: Int = userService.foo + supportService.foo
}
class UserService {
val foo: Int = 1
}
class SupportService {
val foo: Int = 41
}
Test code
package services
import org.specs2.mutable.Specification
import scala.reflect.ClassTag
import java.lang.reflect.Constructor
class Trick {
val m: ClassTag[ReportService] = implicitly
val classLoader: ClassLoader = m.runtimeClass.getClassLoader
val trick: ReportService = Trick.createInstance[ReportService](m.runtimeClass, classLoader)
}
object Trick {
def createInstance[T <: AnyRef](klass: Class[_], loader: ClassLoader)(implicit m: ClassTag[T]): T = {
val constructors = klass.getDeclaredConstructors.toList.sortBy(_.getParameterTypes.size)
val constructor = constructors.head
createInstanceForConstructor(klass, constructor, loader)
}
private def createInstanceForConstructor[T <: AnyRef : ClassTag]
(c: Class[_], constructor: Constructor[_], loader: ClassLoader): T = {
constructor.setAccessible(true)
// This can be implemented generically, but I don't remember how to deal with variadic functions
// generically. IIRC even more reflection.
if (constructor.getParameterTypes.isEmpty)
constructor.newInstance().asInstanceOf[T]
else if (constructor.getParameterTypes.size == 1) {
// not implemented
null.asInstanceOf[T]
} else if (constructor.getParameterTypes.size == 2) {
val types = constructor.getParameterTypes.toSeq
val param1 = createInstance(types(0), loader)
val param2 = createInstance(types(1), loader)
constructor.newInstance(param1, param2).asInstanceOf[T]
} else {
// not implemented
null.asInstanceOf[T]
}
}
}
// NB: no need to #Inject here. The specs2 framework does it for us.
// It sees spec with parameter, and loads it for us.
class ReportServiceSpec (trick: Trick) extends Specification {
"ReportService" should {
"Work" in {
trick.trick.foo mustEqual 2
}
}
}
And that expectedly fails with
[info] ReportService should
[error] x Work
[error] '42' is not equal to '2' (FooSpec.scala:46)
If you don't need runtime dependency injection, then it's better to use cake pattern, and forget reflection all-together.
My colleague suggested a "low-tech" workaround. In the test, instantiate service classes with new:
class ReportServiceSpec extends Specification {
val service = new ReportService(new UserService, new SupportService)
// ...
}
This also works:
class ReportServiceSpec #Inject()(userService: UserService) extends Specification {
val service = new ReportService(userService, new SupportService)
// ...
}
Feel free to post more elegant solutions. I've yet to see a simple DI solution that works (with Guice, Play's default).
Does anyone else find it curious that Play's default test framework does not play well with Play's default DI mechanism?
Edit: In the end I went with an "Injector" test helper, almost the same as what Eric suggested:
Injector:
package testhelpers
import play.api.inject.guice.GuiceApplicationBuilder
import scala.reflect.ClassTag
/**
* Provides dependency injection for test classes.
*/
object Injector {
lazy val injector = (new GuiceApplicationBuilder).injector()
def inject[T: ClassTag]: T = injector.instanceOf[T]
}
Test:
class ReportServiceSpec extends Specification {
val service = Injector.inject[ReportService]
// ...
}

Play framework with Gzip not working

As you know, play! introduced Gzip encoding in 2.2.0 version.
Unfortunately, after updating project and updating play, it doesn't work.
[error] ...\app\Global.scala:4: object filters is not a member of package play
[error] import play.filters.gzip.GzipFilter
[error] ^
[error] ...\app\Global.scala:8: not found: type GzipFilter
[error] object Global extends WithFilters(new GzipFilter) with GlobalSettings {
[error] ^
[error] two errors found
[error] (compile:compile) Compilation failed
It doesn't work even if I create project form console play new TEST.
However in C:\play-2.2.0\framework\src\play-filters-helpers\src\main\scala\play\filters\gzip I have both Gzip.scala and GzipFilter.scala.
My \app\Global.scala looks like that:
import play.api._
import play.api.mvc._
import play.api.mvc.Results._
import play.filters.gzip.GzipFilter
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
object Global extends WithFilters(new GzipFilter) with GlobalSettings {
override def onStart(app: Application) {
Logger.info("Application has started")
}
override def onStop(app: Application) {
Logger.info("Application shutdown")
}
override def onError(request: RequestHeader, ex: Throwable) = Future { InternalServerError("{}") }
override def onBadRequest(request: RequestHeader, error: String) = Future { BadRequest("{}") }
override def onHandlerNotFound(request: RequestHeader) = Future { NotFound("{}") }
}
What am I doing wrong? Has anyone made that working?
In Build.scala, just add "filters" to your app dependencies
val appDependencies = Seq(
jdbc, cache, filters, ...
)
or, if you are doing it with build.sbt
libraryDependencies ++= Seq(
jdbc, cache, filters, ...
)