import akka.event.Logging.DefaultLogger
abstract class AbstractLogger extends DefaultLogger {
override def receive: PartialFunction[Any, Unit] = {
case msg => super.receive(msg)
}
}
final class OtherLogger extends AbstractLogger {
override def receive: PartialFunction[Any, Unit] = {
case msg => super.receive(msg)
}
}
This code works fine in scala 2 but in scala 3 fails on the super.receive line in OtherLogger with:
error overriding method super$receive in class AbstractLogger of type => OtherLogger.this.Receive;
method super$receive of type => PartialFunction[Any, Unit] needs `override` modifier
https://scastie.scala-lang.org/F2cPEyvHR8GSVrpxjtZnyg
Why does this fail to build?
Related
I have the following case class:
trait Event
object Event {
case class ProducerStreamActivated[T <: KafkaMessage](kafkaTopic: String, stream: SourceQueueWithComplete[T]) extends Event
}
trait KafkaMessage
object KafkaMessage {
case class DefaultMessage(message: String, timestamp: DateTime) extends KafkaMessage {
def this() = this("DEFAULT-EMPTY-MESSAGE", DateTime.now(DateTimeZone.UTC))
}
case class DefaultMessageBundle(messages: Seq[DefaultMessage], timeStamp: DateTime) extends KafkaMessage {
def this() = this(Seq.empty, DateTime.now(DateTimeZone.UTC))
}
}
In one of my Actor, I have the following method that identifies the actual Type:
class KafkaPublisher[T <: KafkaMessage: TypeTag] extends Actor {
def paramInfo[T](x: T)(implicit tag: TypeTag[T]): Unit = {
val targs = typeOf[T] match { case TypeRef(_, _, args) => args }
println(s"type of $x has type arguments $targs")
}
implicit val system = context.system
val log = Logging(system, this.getClass.getName)
override final def receive = {
case ProducerStreamActivated(_, stream) =>
paramInfo(stream)
log.info(s"Activated stream for Kafka Producer with ActorName >> ${self.path.name} << ActorPath >> ${self.path} <<")
context.become(active(stream))
case other =>
log.warning("KafkaPublisher got some unknown message while producing: " + other)
}
def active(stream: SourceQueueWithComplete[KafkaMessage]): Receive = {
case msg: T =>
stream.offer(msg)
case other =>
log.warning("KafkaPublisher got the unknown message while producing: " + other)
}
}
object KafkaPublisher {
def props[T <: KafkaMessage: TypeTag] =
Props(new KafkaPublisher[T])
}
I create an instance of the ProducerStreamActivated(...) in a parent Actor like this:
val stream = producerStream[DefaultMessage](producerProperties)
def producerStream[T: Converter](producerProperties: Map[String, String]): SourceQueueWithComplete[T] = {
if (Try(producerProperties("isEnabled").toBoolean).getOrElse(false)) {
log.info(s"Kafka is enabled for topic ${producerProperties("publish-topic")}")
val streamFlow = flowToKafka[T](producerProperties)
val streamSink = sink(producerProperties)
source[T].via(streamFlow).to(streamSink).run()
} else {
// We just Log to the Console and by pass all Kafka communication
log.info(s"Kafka is disabled for topic ${producerProperties("publish-topic")}")
source[T].via(flowToLog[T](log)).to(Sink.ignore).run()
}
}
When I now print the Type that is contained in the stream SourceQueueWithComplete[T] in my child actor, I get to see the base class KafkaMessage contained instead of the expected DefaultMessage. Any ideas how to mitigate this?
In your KafkaPublisher's receive method, you pattern match on a ProducerStreamActivated without any type parameters (you can't match on one with parameters because of type erasure), and in that method, the implicit TypeTag passed to paramInfo is decided at compile-time, at which point it is just a TypeTag[KafkaMessage].
One way you should be able to work around this is to just have the ProducerStreamActivated class carry its own type tag with it, i.e.:
case class ProducerStreamActivated[T <: KafkaMessage](kafkaTopic: String, stream: SourceQueueWithComplete[T])(implicit val tag: TypeTag[T]) extends Event
Then rather than summoning one implicitly in the receive method, just do msg.tag.
This should work because at the point you actually create the ProducerStreamActivated, you do have the compile-time type parameter info (it's DefaultMessage) and so that will be the type tag the compiler fills in, and you can then just keep a reference to that.
Say I have the below:
type Receive = PartialFunction[Any, Unit]
trait Functionality {
/**
* A set containing all Receive functions
*/
var allReceives: Set[Receive] = Set[Receive]()
}
Now other trait's can extend Functionality and do awesome stuff. Example:
trait LoadBalancer extends Functionality{
def body:Receive = {
case ...
}
allReceives += body
}
And ultimately my class:
class Main with LoadBalancer with SecurityFunctionality
with OtherFunctionality with Functionality{
def receive = {
case x if allReceives.foldLeft(false) { (z, f) => if (f isDefinedAt x) { f(x); true } else z } == true => ()
}
def body: Receive = {
}
allReceives += body
}
Question: What I wish to do is, in Main I need to call body function of all the traits that I have inherited. This way my code can be loosely coupled and I can add/remove functionality at a go.
The above works, but I do not like it as the compiler cannot guarantee that any trait that extends Functionality should add its body to allReceives.
I cannot declare def body:Receive in Functionality as then my implementation in Main will override body implementations of other traits. I am sure there should be a smarter way!
On second thought, composition really might be a better option here. This is a simpler solution, without any funny "abstract override"s:
object Main {
type Receive = PartialFunction[Any, Unit]
trait Receiver {
def receive: Receive
}
class LoadBalancer extends Receiver {
override def receive: Receive = {
case "one" => println("LoadBalancer received one")
}
}
class OtherFunctionality extends Receiver {
override def receive: Receive = {
case "two" => println("OtherFunctionality received two")
}
}
class MainFunctionality extends Receiver {
override def receive: Receive = {
case "three" => println("MainFunctionality received three")
}
}
class CompositeReceiver(receivers: List[Receiver]) extends Receiver {
override def receive: Receive = {
case msg =>
receivers.find(_.receive.isDefinedAt(msg)) map (_.receive(msg))
}
}
def main(args: Array[String]) {
val main = new CompositeReceiver(List(new OtherFunctionality, new LoadBalancer, new MainFunctionality))
main.receive("one")
main.receive("two")
main.receive("three")
}
}
This does not really answer your question, but here is a solution using the stackable traits pattern. Alas you still need to call super.receive as the last case in each trait, but I could not find a way around that yet.
object Main {
type Receive = PartialFunction[Any, Unit]
trait Receiver {
def receive: Receive
}
trait LoadBalancer extends Receiver {
abstract override def receive: Receive = {
case "one" => println("LoadBalancer received one")
case msg => super.receive(msg)
}
}
trait OtherFunctionality extends Receiver {
abstract override def receive: Receive = {
case "two" => println("OtherFunctionality received two")
case msg => super.receive(msg)
}
}
class Main extends Receiver {
override def receive: Receive = {
case "three" => println("Main received three")
}
}
def main(args: Array[String]) {
val main = new Main with OtherFunctionality with LoadBalancer
main.receive("one")
main.receive("two")
main.receive("three")
}
}
I have a trait and implementing akka actor that can't properly differentiate the types of incoming messages due to type erasure, and so the first case is matching all messages.
I'm using scala 2.10.x, and from reading many other answers I know that it is possible to recover type information inside a trait using TypeTag or ClassTag, but I can't figure out how to apply it (if it is possible) within the akka receive.
My (very simplified) example is as follows. Is it possible properly match the generic types?
package com.ebay.box.canada.batch.jobs.siteMap
import akka.actor.Actor
import akka.actor.ActorSelection
import akka.actor.Actor.Receive
import scala.reflect.ClassTag
trait MessageProcessor[A,B] {
this: Actor =>
val destA: ActorSelection
val destB: ActorSelection
def processA(a: A): A
def processB(a: B): B
def receive: PartialFunction[Any,Unit] = {
case a: A =>
destA ! processA(a)
case b: B =>
destB ! processB(b)
}
}
class StringIntProcessor(val destA: ActorSelection, val destB: ActorSelection) extends MessageProcessor[String,Int] with Actor {
def processA(a: String) = { a + "1" }
def processB(b: Int) = { b + 1 }
}
I don't think you can get at TypeTag[A] or ClassTag[A] in your trait -- type tags/class tags are always part of the implicit argument list to a method call. You might be able to use an abstract class instead, with implicit constructor arguments:
import scala.reflect.runtime.universe._
abstract class MessageProcessor[A,B]()(implicit cta: ClassTag[A], ctb: ClassTag[B]) {
def receive = {
case a: Any if a.getClass() == cta.runtimeClass =>
process(a.asInstanceOf[A])
...
}
...
}
(Not tested!)
Supposing that you can change the code that sends the message, can I suggest the following design instead? MessageProcessor is now a typeclass, so that you can add any number of message types. By sending a closure as the message, you can smuggle any amount of context into the call site.
class MessageReceiver extends Actor {
def receive = {
case fn: Function0[Unit] =>
fn()
}
}
trait MessageProcessor[A] {
val dest: ActorSelection
def process(a: A): A
}
object Processors {
implicit object StringProcessor extends MessageProcessor[String] {
val dest: ActorSelection = Wellknown.stringDest
def process(a: String): String = a + "1"
}
implicit object IntProcessor extends MessageProcessor[Int] {
val dest: ActorSelection = Wellknown.intDest
def process(a: Int): Int = a + 1
}
def sendMessage[A](msg: A)(implicit ev:[MessageProcessor[A]]): Unit = {
val block: Function0[Unit] = { () =>
ev.dest ! ev.process(msg)
}
val msgDest = system.actorOf[Props[MessageReceiver]], "msgDest")
msgDest ! block
}
}
(Also not tested!)
Consider these two traits:
trait Poked extends Actor {
override def receive = {
case Poke(port, x) => ReceivePoke(port, x)
}
def ReceivePoke(port: String, x: Any)
}
trait Peeked extends Actor {
override def receive = {
case Peek(port) => ReceivePeek(port)
}
def ReceivePeek(port: String)
}
Now consider I can create a new Actor that implements both traits:
val peekedpoked = actorRef(new Actor extends Poked with Peeked)
How do I compose the receive handlers? i.e., the receiver should be something like the following code, though "automatically generated" (i.e., all traits should compose):
def receive = (Poked.receive: Receive) orElse (Peeked.receive: Receive) orElse ...
You can use super[T] to reference members of particular super classes/traits.
For example:
trait IntActor extends Actor {
def receive = {
case i: Int => println("Int!")
}
}
trait StringActor extends Actor {
def receive = {
case s: String => println("String!")
}
}
class IntOrString extends Actor with IntActor with StringActor {
override def receive = super[IntActor].receive orElse super[StringActor].receive
}
val a = actorOf[IntOrString].start
a ! 5 //prints Int!
a ! "Hello" //prints String!
Edit:
In response to Hugo's comment, here's a solution that allows you to compose the mixins without having to manually wire their receives together. Essentially it involves a base trait with a mutable List[Receive], and each mixed-in trait calls a method to add its own receive to the list.
trait ComposableActor extends Actor {
private var receives: List[Receive] = List()
protected def registerReceive(receive: Receive) {
receives = receive :: receives
}
def receive = receives reduce {_ orElse _}
}
trait IntActor extends ComposableActor {
registerReceive {
case i: Int => println("Int!")
}
}
trait StringActor extends ComposableActor {
registerReceive {
case s: String => println("String!")
}
}
val a = actorOf(new ComposableActor with IntActor with StringActor).start
a ! 5 //prints Int!
a ! "test" //prints String!
The only thing to keep in mind is that the order of the receives should not be important, since you won't be able to easily predict which one is first in the chain, though you could solve that by using a mutable hashmap instead of a list.
You can use empty Receive in base actor class and chain receives in their definitions.
Sample for Akka 2.0-M2:
import akka.actor.Actor
import akka.actor.Props
import akka.event.Logging
import akka.actor.ActorSystem
class Logger extends Actor {
val log = Logging(context.system, this)
override def receive = new Receive {
def apply(any: Any) = {}
def isDefinedAt(any: Any) = false
}
}
trait Errors extends Logger {
override def receive = super.receive orElse {
case "error" => log.info("received error")
}
}
trait Warns extends Logger {
override def receive = super.receive orElse {
case "warn" => log.info("received warn")
}
}
object Main extends App {
val system = ActorSystem("mysystem")
val actor = system.actorOf(Props(new Logger with Errors with Warns), name = "logger")
actor ! "error"
actor ! "warn"
}
I have some events in my model and some handling logic. I want organize communication logic throw Actors. But how I can inherit handling logic without specifying act() in each concrete class
Simplified example
class Event {}
case class FooEvent(str : String) extends Event
case class BarEvent(i : java.lang.Integer) extends Event
trait FooListener extends Actor {
def act() {
react{
case FooEvent => print("foo received")
}
}
}
trait BarListener extends Actor {
def act() {
react{
case BarEvent => print("bar received")
}
}
}
class ListensOnlyBar extends BarListener{}
//can't be done:
//error: overriding method act in trait FooListener of type ()Unit;
//method act in trait BarListener of type ()Unit needs `override' modifier
//class ListensBarAndFoo extends FooListener with BarListener{
class ListensBarAndFoo extends FooListener with BarListener{}
react expects PartialFunction[Any, Unit] and you can nicely compose them together. Here is an example:
type Listener = PartialFunction[Any, Unit]
val foo: Listener = {
case FooEvent => print("foo received")
}
val bar: Listener = {
case BarEvent => print("bar received")
}
case class GenericListener(listener: Listener) extends Actor {
def act() {
react(listener)
}
}
GenericListener(bar)
GenericListener(foo orElse bar)