I am new to scala/akka. I need to create a trait and from this trait, to retrieve actors from a context or directly from an actorSystem.
But I don't want this trait to either extends Actor, nor force to be mixed with an Actor.
Is there a way to do that?
Thanks.
Welcome to Akka :-)
You should create a trait with an abstract method, that will be used to retrieve the actor system, for example like this:
trait DoesThings {
def system: ActorSystem
def findActor(name: String) = // do actor selection using system here
}
object Example extends DoesThings {
val system = ActorSystem("example")
val ref = findActor
}
Happy hakking!
You can put an actor system val in the trait.
And with instantiation you will pass used actor system to it.
You could try something like this:
trait ActorLookup{
def actorSelection(path:ActorPath)(implicit fact:ActorRefFactory) = fact.actorSelection(path)
def actorSelection(path:String)(implicit fact:ActorRefFactory) = fact.actorSelection(path)
}
class ActorBasedImpl extends Actor with ActorLookup{
def receive = {
case _ =>
val ref = actorSelection("/foo")
}
}
class NonActorBasedImpl extends ActorLookup{
implicit val system = ActorSystem("foo")
...
val ref = actorSelection("/user/foo")
}
Within an Actor, you already have an implicit ActorRefFactory in scope so no need to define one. If you wanted to use the ActorSystem instead there, you could just pass it explicitly like so:
actorSelection("/user/foo")(context.system)
Outside an Actor, it's more likely you will be using an ActorSystem instead of an ActorContext to perform lookups, so that's why an implicit ActorSystem was defined. But again, you don't have to define it as an implicit and could just use it explicitly if desired.
Related
I have an actor to which I want inject dependency using mixin. Code:
trait ProductsAware {
def getProducts: List[Product]
}
trait MyActor extends Actor with ProductsAware {
val products = getProducts
...
}
As you can see I'm just trying to decouple MyActor from concrete instance of ProductsAware trait, and provide concrete instance in other place (when creating actor).
And this is concrete implementation of ProductsAware trait:
trait ProductsAwareFirstImpl {
override def getProducts = {List(new Product())}
}
And I want to create new MyActor and inject to MyActor this concrete implementation ProductsAwareFirstImpl:
system.actorOf(Props[MyActor])
The problem is that is not safe at compile time, i.e. anyone can forget to mix the ProductsAwareFirstImplto MyActor
You can use a different Actor Props construction technique, namely the Props(new Actor) as documented here. Just make sure you are careful and not closing over any state, e.g. putting it in a object and calling it via a method should be safe. This is described in the documentation, but a quick mockup would look like this:
object MyActor {
def newActorWithFirstImpl = new MyActor with ProductsAwareFirstImpl
}
//...
system.actorOf(Props(MyActor.newActorWithFirstImpl))
To be sure that some trait is mixed to you actor you may user explicit self type reference:
trait MyActor extends Actor {
self: ProductsAware =>
val products = getProducts
// ...
}
So no one could instantiate MyActor without mixin ProductsAware
How does one create a TestActorRef inside a test class. Specifically, I have the following test set up...
class MatchingEngineSpec extends TestKit(ActorSystem("Securities-Exchange"))
with FeatureSpecLike
with GivenWhenThen
with Matchers {
val google = Security("GOOG")
val ticker = Agent(Tick(google, None, None, None))
val marketRef = TestActorRef(new DoubleAuctionMarket(google, ticker) with BasicMatchingEngine)
val market = marketRef.underlyingActor
...when I run the tests everything passes, but after shutting down the ActorSystem I get this long error trace...
[ERROR] [03/10/2015 15:07:55.571] [Securities-Exchange-akka.actor.default-dispatcher-4] [akka://Securities-Exchange/user/$$b] Could not instantiate Actor
Make sure Actor is NOT defined inside a class/trait,
if so put it outside the class/trait, f.e. in a companion object,
OR try to change: 'actorOf(Props[MyActor]' to 'actorOf(Props(new MyActor)'.
akka.actor.ActorInitializationException: exception during creation
I came across this previous question, but the accepted answer didn't work for me in this case.
In case it is relevant, here is the definition of the DoubleAuctionMarket actor...
class DoubleAuctionMarket(val security: Security, val ticker: Agent[Tick]) extends Actor with ActorLogging {
this: MatchingEngine =>
...
I had the same issue because I was using a companion object to inject the config into MyActor without passing it explicitly:
object MyActor {
def apply(): MyActor = new MyActor(MyActorConfig.default)
val props = Props(new MyActor(MyActorConfig.default))
}
Then I can just do:
val myActorRef = system.actorOf(MyActor.props, "actorName")
The error is related to passing the arguments explicitly in the test here:
TestActorRef(new DoubleAuctionMarket(google, ticker))
I would try to remove the with BasicMatchingEngine as vptheron said, use the constructor without mixing anything else. Try also with an argument less actor if that is not enough.
That must fix your problem since there are no issues with just:
TestActorRef(new DoubleAuctionMarket(google, ticker))
I'm looking for the best syntax for having contained classes pick up the implicits exposed by their containing classes?
The scenario I have has two dependencies abstracted for testing: The creation of the application's actorsystem, and a webclient that happens to require the actorsystem as well:
trait Core {
implicit def system: ActorSystem
}
trait WebClient {
implicit def system: ActorSystem
}
trait Api extends WebClient {
...
}
trait Server extends Core {
def api: Api
val service = system.actorOf(Props(new Service(api)))
}
Now, i create a new App which provides the actorsystem and api, but the Api needs an implicit actorsystem, and the only way I've figured out is to manually provide it like this:
object ServerApp extends App with Core {
implicit val system = ActorSystem("foo")
val api = new Api {
override implicit def system = implicitly[ActorSystem]
}
}
Is there a better syntax for having WebClient pick up the implicit from Core? I can't have it extend Core, since it is contained by the Core implementation and required as a dependency for something else that is contained there. But override implict def system = implicitly[ActorSystem] seems rather hamfisted for something that should be, er, implicit
You're shadowing the implicit value since they have the same name.
You might consider
class Api()(implicit val system: ActorSystem)
and
val api = new Api
I am wanting to test one of my akka actors, it uses slick to get the information from the database. In my actor I have this bit of code
CardStationPermissions.retrieveByStationID(stationID).foreach(card => {
I want to know how can I mock that function to change the output instead of relaying on whats in the database?
It's really difficult to mock things that are being called in a static way (in this case, a call on an object as opposed to an instance of a class). When you need to be able to mock and test things like this, I tend to agree with Mustafa's suggestion that creating a trait to represent the relevant methods to mock. A simple example would look as follows:
case class MyObject(id:Long)
trait MyDao{
def getData(input:String):List[MyObject] = ...
}
object MyDao extends MyDao
class MyActor extends Actor{
val myDao:MyDao = MyDao
def receive = {
case param:String => sender ! myDao.getData(param)
}
}
Here you can see that I have a trait to represent my dao methods (only 1 for this example) and then I mix that trait into a scala object as the default instantiation of that trait. When I setup my dao in my actor, I explicitly type it to the trait so that I can substitute a mock impl of that trait later.
So then if I wanted a simple test showing mocking, it could look something like this (via specs2):
class MyActorTest(_system:ActorSystem) extends TestKit(_system)
with Specification with Mockito with ImplicitSender{
def this() = this(ActorSystem("test"))
trait scoping extends Scope{
val mockDao = mock[MyDao]
val actor = TestActorRef(new MyActor{
override val myDao = mockDao
})
}
"A request to get data" should{
"pass the input to the dao and return the result to the sender" in new scoping{
mockDao.getData("foo") returns List(MyObject(1))
actor ! "foo"
expectMsg(List(MyObject(1)))
}
}
}
I am playing with the Play! framework and I wanted to create a factory called Services which will create new actors. I have this so far
class UserRegistration extends Actor {
def receive = {
case "foo" => "bar"
}
}
object UserRegistration {
val path: String = "user/registration"
}
object Services {
val system = ActorSystem("Services")
def apply[A<:Actor]: ActorRef = system.actorOf(Props[A], A.path)
}
And I wanted to create and pass messages to actors like this:
Services[UserRegistration] ? "hello"
but I get errors of the type could not find implicit value for evidence parameter of type ClassManifest[A]. Can anyone please tell me what am I doing wrong here? And if this is a valid construction in general (a best practice). I am pretty new in Scala and still learning stuff.
Thanks!
senia's answer works too, but if you want to specify a common path for each type of actor, you need a second implicit parameter(the first being the ClassManifest so that you can specify a path for each type of actor. Keep in mind that actor names have to be unique though, so you have to add something to that path.
First you define a class that holds the Path:
case class Path(value:String)
Then you define an implicit value in the companion object of your actor class:
object SomeActor {
implicit val path = Path("SomeActor")
}
Finally you modify the apply method to take an implicit class manifest as well as an implicit path.
def apply[A<:Actor](implicit cm:ClassManifest[A], path:Path[A]): ActorRef =
system.actorOf(Props[A], path.value + someIndex)
Method apply of object Props implicitly takes parameter of type ClassManifest[T].
apply [T <: Actor] (implicit arg0: ClassManifest[T])
You have to add such parameter into your method:
def apply[A<:Actor : ClassManifest]: ActorRef = system.actorOf(Props[A])