I am busy with a major refactoring task on some legacy Scala/Akka code, and am being haunted by a construct that I am unable to explain, which is hampering my effort:
trait PerRequestCreator {
this: Actor =>
def perRequest(<some_params>): ActorRef = { body of function }
}
Which is then used as such:
class SomeActor extends PerRequestCreator with Actor {
def processRequest: Route = {
perRequest(<some_params_passed>)
}
}
I am having trouble understanding the this: Actor => ... part of the trait.
It's called self-type, and it expresses a requirement for the PerRequestCreator to be mixed in into something that extends Actor.
It's useful because now you can use anything defined in Actor inside the definition of PerRequestCreator and the compiler will check that you can only extend PerRequestCreator if you also extend Actor.
Example:
class SomeClass extends PerRequestCreator // this won't compile
class SomeClass extends PerRequestCreator with Actor // this is ok
You can read more about it here: https://docs.scala-lang.org/tour/self-types.html
Related
I am trying something with Akka Typed and Scala, actually something very simple as concept but I could not make it work so may be you can help me.
All my Actors will have one common Signal, so I try to place it to a base class and let my all Actors share it but it the compiler refuse it in the MessageAdapter....
So my code looks like following....
object ContractActor {
sealed trait ContractEvent extends BaseEvent
final case class onApprove(payload: Payload) extends ContractEvent
}
class ContractActor(ctx: ActorContext[ContractEvent]) extends BaseActor {
val listingAdapter = : ActorRef[Receptionist.Listing] = ctx.
messageAdapter(
listing => onAddRelatedEvent(listing)
}
and base actor
object BaseActor {
trait BaseEvent;
final case class onAddRelatedEvent(listing: Receptionist.Listing) extends BaseEvent
}
The compiler complains about onAddRelatedEvent is not known on ContractEvent which surprise me because ContractEvent extends BaseEvent....
What am I missing here....
Class ContractActor extending BaseActor does not automatically bring BaseActor's companion object into scope. To bring it into scope, just import it inside class ContractActor:
import BaseActor._
Alternatively, you could move the inner trait/case class into BaseActor's companion class.
I wrote an Akka base-actor that can handle some common messages. I want to reuse this basic behavior in a sub-actor, by extending the base-actor (not by composition of the base-actor).
I have seen several approaches in previous questions. They are all valid but also may be improved:
How extend behaviour of super actor in akka
and
How do I best share behavior among Akka actors?
To make the implementation cleaner, I am trying to achieve the following:
When defining the sub-actor, I try to extend only the base-actor (not both Actor and sub-actor). However, I was not able to force the compiler to do this.
I also try to not rename the receive partial function, because it is a kind of convention.
Here is a sample of my implementation:
//This is the base-actor that implements the common behavior
trait BetterActor extends Actor {
abstract override def receive = {
super.receive orElse { case _ => println("Missing pattern!") }
}
}
//This is the actor that implements the additional behavior.
//I actually wanted to extend BetterActor. It was not possible.
class MyActor extends Actor {
def receive = {
case i: Int =>
println(s"Yay!!! Got $i")
}
}
Here are two alternative ways how I can create an instance of the sub-actor, which combines both the common and the additional behaviors:
//1.
val myBetterActor = system.actorOf(Props(new MyActor with BetterActor), "myBetterActor")
//2.
class MyBetterActor extends MyActor with BetterActor
val myBetterActor = system.actorOf(Props[MyBetterActor], "myBetterActor")
Finally, I may invoke the sub-actor by:
myBetterActor ! 2
myBetterActor ! "a"
Problems with my implementation:
When I create an instance of the sub-actor, only then I can mix in the base-actor, either directly (1) or by defining a new class that mixes in the base-actor.
Like I said before, I would prefer to mix in the base-actor when I define the sub-actor. Not when I try to create an instance of the sub-actor.
P.S. It's fascinating that the designers of this framework did not see it necessary to make this common requirement easy to accomplish.
i suppose as long as you're not trying to override behavior with BetterActor, you could try something like this:
trait BetterActor extends Actor {
override def unhandled(message: Any): Unit = message match {
case e: CommonMessage => println("COMMON!")
case e => super.unhandled(e)
}
}
class MyActor extends BetterActor {
override def receive = {
case i: Int => println(s"Yay!!! Got $i")
}
}
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
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 have traits from two third party libraries that I'm trying to mix in to my own trait. They both define implicit vals named log.
However, they are of different types - one is an SLF4J Logger, the other is a Spray LoggingContext (which is really an Akka LoggingAdapter). In fact the second trait is from Spray, it's an HttpServer. (Not the most recent version you can find on Github which no longer has that val).
So, here's the code (library one renamed because it's proprietary, the Spray code snipped to show just relevant part):
object LibraryOneShim {
trait LibraryOne {
implicit val log: org.slf4j.Logger = ...
}
}
// https://github.com/spray/spray/blob/a996a5b6bdd830e613583fed86e87bf049fdb8c0/spray-routing/src/main/scala/spray/routing/HttpService.scala
trait HttpService extends Directives {
val log = LoggingContext.fromActorRefFactory // this is a LoggingContext/LoggingAdapter
}
trait MyTrait extends HttpService with LibraryOne {
val myRoute = ...
}
class MyActor extends Actor with MyTrait {
def receive = runRoute(myRoute)
}
This won't compile. The compiler complains:
error: overriding lazy value log in trait HttpService of type
java.lang.Object with spray.util.LoggingContext; lazy value log in
trait LibraryOne$class of type org.slf4j.Logger needs `override'
modifier trait DemoService extends HttpService with LibraryOne {
Is there any way I can mix in these two traits together?
As far as I can tell the only way is to create a CombinedLogger
class CombinedLogger(l1:Logger, l2:LoggingAdapter) extends Logger with LoggingAdapter {
// proxy methods to the correct logger
}
If both loggers were declared as def you could use it like this:
override def log = new CombinedLogger(super[LibraryOne].log, super[HttpService].log)
In this case it's tricky because they are defined as val which tell the Scala compiler they are a single value that will not change. And because of that it will not allow you to call super.log. So you would need to copy the logic of the overridden traits.
The other tricky part in this case is that you would need to proxy 50+ methods in the CombinedLogger.