How to inject services into actors using the Play 2.4? - scala

I am able to inject services into my Application class with no issues. But somehow I am unable to inject into the actors themselves.
My actor:
class PollerCrow #Inject()(
#Named("pollService") pollService: PollService[List[ChannelSftp#LsEntry]]
, #Named("redisStatusService") redisStatusService: StatusService
, #Named("dynamoDBStatusService") dynamoDbStatusService: StatusService
) extends BaseCrow {
... impl and stuff ...
}
My actor's companion object:
object PollerCrow extends NamedActor {
override def name: String = this.getClass.getSimpleName
val filesToProcess = ConfigFactory.load().getString("poller.crow.files.to.process")
def props = Props[PollerCrow]
}
I'm getting the following when I run it:
IllegalArgumentException: no matching constructor found on class watcher.crows.PollerCrow for arguments []
How can I fix this?
Edit:
I have binded my actors:
class ActorModule extends AbstractModule with AkkaGuiceSupport {
override def configure() {
bindPollerActors()
}
private def PollActors() = {
bindActor[PollerCrow](PollerCrow.name)
}
}
Edit 2:
Additional details to the class:
abstract class BaseCrow extends Crow with Actor with ActorLogging
class PollerCrow #Inject()(
#Named(ServiceNames.PollService) pollService: PollService[List[ChannelSftp#LsEntry]]
, #Named(ServiceNames.RedisStatusService) redisStatusService: StatusService
, #Named(ServiceNames.DynamoDbStatusService) dynamoDbStatusService: StatusService
) extends BaseCrow {
override def receive: Receive = {
...
}
}
object PollerCrow extends NamedActor {
override def name: String = this.getClass.getSimpleName
def props = Props[PollerCrow]
}
trait NamedActor {
def name: String
final def uniqueGeneratedName: String = name + Random.nextInt(10000)
}

You might to make Guice aware of you actors. This is clean approach:
import com.google.inject.AbstractModule
import play.api.libs.concurrent.AkkaGuiceSupport
class ActorModule extends AbstractModule with AkkaGuiceSupport {
override def configure(): Unit = {
bindActor[YourActor]("your-actor")
}
}
#Singleton
class YourActor #Inject()(yourService: IYourService) extends Actor {
override def receive: Receive = {
case msg => unhandled(msg)
}
}
And application.conf:
play.modules {
enabled += "ActorModule"
}
For those who don't want to hassle, just call injector directly and don't forget to import Application to scope:
Play.application.injector.instanceOf[YourService]
Play.application.injector.instanceOf(BindingKey(classOf[YourService]).qualifiedWith("your-name"));

Related

scala: how to inject inside guice module

i am new in guice here is my code
trait MyRepository
class MyRepositoryImp extends MyRepository
trait MyService
class MyServiceImp #Inject()(myRepository:MyRepository) extends MyService
class Demo #Inject(myService:MyService)
class RepositoryModule extends AbstractModule {
override protected def configure(): Unit = {
bind(classOf[MyRepository]).toInstance(new MyRepositoryImpl)
}
}
class ServiceModule extends AbstractModule {
override protected def configure(): Unit = {
bind(classOf[MyService]).toInstance(new MyService(//what should i pass in here?))
}
}
my question is in ServiceModule how can i pass the injected MyRepository param in MyService constructor
Try with #Provides annotation
import com.google.inject.{AbstractModule, Guice, Inject, Injector, Provides}
import scala.jdk.CollectionConverters._
trait MyRepository {}
class MyRepositoryImp extends MyRepository {}
trait MyService {}
class MyServiceImp #Inject() (myRepository: MyRepository) extends MyService {}
class Demo #Inject() (myService: MyService) { println("Woohoo, I am wired!") }
class Module extends AbstractModule {
#Provides def repository: MyRepository = new MyRepositoryImp
#Provides def service(repo: MyRepository): MyService = new MyServiceImp(repo)
#Provides def demo(service: MyService): Demo = new Demo(service)
}
object guiceExample extends App {
val injector: Injector = Guice.createInjector(List(new Module).asJava)
val demo = injector.getInstance(classOf[Demo])
}
which outputs Woohoo, I am wired!.

top level naming in chisel3

class generator(options: Map[String, Any]) {
trait for_module extends abstractModule {
//generates trait with params
}
class my_module extends abstractModule with for_module
def exec = {
...
Driver.execute(Array("-tn", "SomeName", "-td", "SomePath"), () => new my_module)
...
}
}
object generator {
def main(args: Array[String]) = {
...
val a = generator(someopts)
a.exec
}
}
In this code flag -tn should change name of top-level circuit, but it changes only top-level filename. Top module names like "module generatormy_module", but i wants to generate name dynamically from params.
Is dat bug? Or how i can change a top-level module name?
PS: suggestName method doesn't works too!
The flag -tn is not intended to change the top-level circuit, only to specify it and use it as a default in filenames. The way to specify the name of a Chisel module is to override the desiredName method. You can override it with an argument to the Module constructor to make it more programmable. Modifying the above example:
class generator(options: Map[String, Any]) {
trait for_module extends abstractModule {
//generates trait with params
}
class my_module(name: String) extends abstractModule with for_module {
override def desiredName = name
}
def exec = {
val topName = "SomeName"
Driver.execute(Array("-tn", topName, "-td", "SomePath"), () => new my_module(topName))
...
}
}
object generator {
def main(args: Array[String]) = {
...
val a = generator(someopts)
a.exec
}
}

How to mock an interface in Guice module with ScalaMock?

How can I simply mock an interface needed for injection in Guice using ScalaMock?
I've ended up using
import org.scalamock.MockFactoryBase
import org.scalatest.exceptions.TestFailedException
trait MyMockFactory extends MockFactoryBase {
type ExpectationException = TestFailedException
override protected def newExpectationException(message: String, methodName: Option[Symbol]): TestFailedException = ???
}
and in TestModule
class TestModule extends AbstractModule with MyMockFactory {
override def configure(): Unit = {
val mockObject = mock[ClassName]
bind(classOf[ClassName]).toInstance(mockObject)
}
}
Use a separate test module by binding mocked instances to class names and use that module to inject objects for your tests.
Test Module goes like this:
class TestModule extends AbstractModule {
override def configure(): Unit = {
val mockObject = mock[ClassName]
bind(classOf[ClassName]).toInstance(mockObject)
}
}
Spec goes like this:
class SomeSpec extends FlatSpec {
val injector = Guice.createInjector(new TestModule)
val mockObject = injector.getInstance(classOf[ClassName])
}

Scala/Akka/Guice dynamically injecting child actors

I would like to be able to create multiple instances of the same parent actor, but with different child actors. I assume this has to be possible with Guice, but I haven't found the solution.
Here is what I have in mind ~
Controller:
class Application #Inject()(#Named(ParentActor.parentActor1) parentActor1: ActorRef,
#Named(ParentActor.parentActor2) parentActor2: ActorRef)
extends Controller {
def index = Action {
parentActor1 ! "Message"
parentActor2 ! "Message"
Ok()
}
}
Parent Actor:
object ParentActor {
final val parentActor1 = "parentActor1"
final val parentActor2 = "parentActor2"
}
class ParentActor #Inject() (childActor: ActorRef) extends Actor {
def receive = {
case "Message" =>
println(s"ParentActor ${self.path} received message...")
childActor ! "Message"
}
}
Child Actor A:
class ChildActorA extends Actor {
def receive = {
case "Message" =>
println("ChildActorA received message...")
}
}
Child Actor B:
class ChildActorB extends Actor {
def receive = {
case "Message" =>
println("ChildActorB received message...")
}
}
Module:
class Modules extends AbstractModule with AkkaGuiceSupport {
override def configure() = {
bindActor[ParentActor](ParentActor.parentActor1)
bindActor[ParentActor](ParentActor.parentActor2)
}
}
What if I wanted "parentActor1" to have have its "childActor" ref point to an instance of ChildActorA and "parentActor2" to have its "childActor" ref point to an instance of ChildActorB? Is this possible to achieve with Guice?
I'm using some code based on https://github.com/rocketraman/activator-akka-scala-guice to accomplish something similar
I'm not using Play, so I have to initialize Guice and bootstrap the actor system
import akka.actor._
import javax.inject.{Inject, Provider, Singleton}
import com.google.inject.AbstractModule
import net.codingwell.scalaguice.InjectorExtensions._
import com.google.inject.Guice
import com.google.inject.Injector
import scala.concurrent.Await
import scala.concurrent.duration.Duration
object Bootstrap extends App {
val injector = Guice.createInjector(
new AkkaModule(),
new ServiceModule()
)
implicit val system = injector.instance[ActorSystem]
val parentActor1 = system.actorOf(ParentActor.props(ChildActorA.name))
val parentActor2 = system.actorOf(ParentActor.props(ChildActorB.name))
parentActor1 ! "Message"
parentActor2 ! "Message"
system.terminate()
Await.result(system.whenTerminated, Duration.Inf)
}
To initialize Guice there are two classes/objects:
One to initialize the extension and inject the actor system where required
import akka.actor.ActorSystem
import AkkaModule.ActorSystemProvider
import com.google.inject.{AbstractModule, Injector, Provider}
import com.typesafe.config.Config
import net.codingwell.scalaguice.ScalaModule
import javax.inject.Inject
object AkkaModule {
class ActorSystemProvider #Inject() (val injector: Injector) extends Provider[ActorSystem] {
override def get() = {
val system = ActorSystem("actor-system")
GuiceAkkaExtension(system).initialize(injector)
system
}
}
}
class AkkaModule extends AbstractModule with ScalaModule {
override def configure() {
bind[ActorSystem].toProvider[ActorSystemProvider].asEagerSingleton()
}
}
another one to create the providers for the children
import javax.inject.Inject
import akka.actor.{Actor, ActorRef, ActorSystem}
import com.google.inject.name.{Named, Names}
import com.google.inject.{AbstractModule, Provides, Singleton}
import net.codingwell.scalaguice.ScalaModule
class ServiceModule extends AbstractModule with ScalaModule with GuiceAkkaActorRefProvider {
override def configure() {
bind[Actor].annotatedWith(Names.named(ChildActorA.name)).to[ChildActorA]
bind[Actor].annotatedWith(Names.named(ChildActorB.name)).to[ChildActorB]
}
#Provides
#Named(ChildActorA.name)
def provideChildActorARef(#Inject() system: ActorSystem): ActorRef = provideActorRef(system, ChildActorA.name)
#Provides
#Named(ChildActorB.name)
def provideChildActorBRef(#Inject() system: ActorSystem): ActorRef = provideActorRef(system, ChildActorB.name)
}
The extension
import akka.actor._
import com.google.inject.Injector
class GuiceAkkaExtensionImpl extends Extension {
private var injector: Injector = _
def initialize(injector: Injector) {
this.injector = injector
}
def props(actorName: String) = Props(classOf[GuiceActorProducer], injector, actorName)
}
object GuiceAkkaExtension extends ExtensionId[GuiceAkkaExtensionImpl] with ExtensionIdProvider {
override def lookup() = GuiceAkkaExtension
override def createExtension(system: ExtendedActorSystem) = new GuiceAkkaExtensionImpl
override def get(system: ActorSystem): GuiceAkkaExtensionImpl = super.get(system)
}
trait NamedActor {
def name: String
}
trait GuiceAkkaActorRefProvider {
def propsFor(system: ActorSystem, name: String) = GuiceAkkaExtension(system).props(name)
def provideActorRef(system: ActorSystem, name: String): ActorRef = system.actorOf(propsFor(system, name))
}
producer
import akka.actor.{IndirectActorProducer, Actor}
import com.google.inject.name.Names
import com.google.inject.{Key, Injector}
class GuiceActorProducer(val injector: Injector, val actorName: String) extends IndirectActorProducer {
override def actorClass = classOf[Actor]
override def produce() = injector.getBinding(Key.get(classOf[Actor], Names.named(actorName))).getProvider.get()
}
and your actors
import javax.inject.Inject
import akka.actor._
object ParentActor {
def props(childName: String)(implicit #Inject() system: ActorSystem) = Props(classOf[ParentActor],system.actorOf(GuiceAkkaExtension(system).props(childName)))
}
class ParentActor (childActor: ActorRef) extends Actor {
def receive = {
case "Message" =>
println(s"ParentActor ${self.path} received message...")
childActor ! "Message"
}
}
object ChildActorA extends NamedActor{
override final val name = "ChildActorA"
def props() = Props(classOf[ChildActorA])
}
class ChildActorA extends Actor {
def receive = {
case "Message" =>
println("ChildActorA received message...")
}
}
object ChildActorB extends NamedActor{
override final val name = "ChildActorB"
def props() = Props(classOf[ChildActorB])
}
class ChildActorB extends Actor {
def receive = {
case "Message" =>
println("ChildActorB received message...")
}
}
the output from sbt
> run
[info] Running Bootstrap
ParentActor akka://actor-system/user/$b received message...
ParentActor akka://actor-system/user/$d received message...
ChildActorB received message...
ChildActorA received message...
[success] Total time: 1 s, completed Jun 14, 2016 1:23:59 AM
You have to explicitly name the children,
It's not the purest or most elegant answer, and I'm sure the code can be optimized, but it allows you to create instances of the same parent with different children.
I'm thinking that you can also use BindingAnnotations

Injecting Akka's TestProbe in place of child actors

I have a parent actor named "manager" which creates several child actors.
These child actors then send back their response via "sender tell", i.e directly back to "manager".
I want to create a unit test for this manager actor, and therefore need to inject a probe to forward the messages from the manager to its children.
I used the following post:
http://www.superloopy.io/articles/2013/injecting-akka-testprobe.html
However i'm still having some trouble getting this done correctly.
In order to simplify the situation, attached is code describing the actors and unit test i wrote for just one child.
Manager class:
trait ManagerChildProvider {
def createTimestampPointChild: Actor
}
trait ProductionManagerChildProvider extends ManagerChildProvider {
def createTimestampPointChild = new TimeDifferenceCalculationActor
}
object Manager {
def apply() = new Manager("cid1") with ProductionManagerChildProvider
}
class Manager(name: String) extends Actor with ActorLogging {
this: ManagerChildProvider =>
#Autowired private val modelParams = new ModelParams //list of parameters
val timeDifference = context.actorOf(Props(createTimestampPointChild))
def receive = {
case p#TimePoint(tPoint) =>
timeDifference ! p
case _ =>
log.error("Unknown message type")
}
}
Child class:
class TimeDifferenceCalculationActor extends Actor with ActorLogging {
var previousTimestamp: Long = -1
def receive = {
case tPoint(timestamp) =>
if (previousTimestamp != -1) {
sender ! Result(1)
}
case _ =>
log.error("Unknown message type")
}
}
Test class:
object BarSpec {
class Wrapper(target: ActorRef) extends Actor {
def receive = {
case x => target forward x
}
}
}
trait ChildrenProvider {
def newFoo: Actor
}
class BarSpec extends TestKitSpec("BarSpec") {
import Manager._
import BarSpec._
trait TestCase {
val probe = TestProbe()
trait TestChildrenProvider extends ManagerChildProvider {
def newBar = new Wrapper(probe.ref)
}
val actor = system.actorOf(Props(new Manager(componentId = "cid1") with TestChildrenProvider))
}
"Bar" should {
"involve child in doing something" in new TestCase {
actor ! tPoint(1)
actor ! tPoint(2)
probe.expectMsg(tPoint(1))
//probe.reply("ReplyFromChild")
//expectMsg("ReplyFromParent")
}
}
}
Additional test class:
abstract class TestKitSpec(name: String) extends TestKit(ActorSystem(name)) with MustMatchers with BeforeAndAfterAll with ImplicitSender with WordSpecLike{
override def afterAll() {
system.shutdown()
}
}
Currently i get the following errors:
Error:(36, 42) object creation impossible, since method > createTimestampPointChild in trait ManagerChildProvider of > type => akka.actor.Actor is not defined
val actor = system.actorOf(Props(new Manager(componentId = "cid1") with TestChildrenProvider))
Error:(11, 16) overriding method run in trait BeforeAndAfterAll of type > (testName: Option[String], args: > org.scalatest.Args)org.scalatest.Status;
method run in trait WordSpecLike of type (testName: Option[String], > args: org.scalatest.Args)org.scalatest.Status needs `abstract override' > modifiers
abstract class TestKitSpec(name: String) extends > TestKit(ActorSystem(name))
any help with these specific errors or with the task in general would be highly appreciated