简体   繁体   中英

How can we override the react construct of scala actors?

The usual way of detecting the type of message received in scala actors is by

loop{
     react{
            case x: String =>
           }
     }

However, I want to know how can we override this implementation of react construct so that we can do implicit logging of the message that is received.

I am trying to implement a use case mentioned below -> 1. Before a message is matched to any case class, I want to write a log statement on console / file showing the occurance of the message. 2. We can log these messages explicitly by println() / log4j logging . However, I want to design a generic logger for scala actors which will log all the messages sent or received.

Any help in this regard will be helpful. Thanks in advance

First, be aware that the Scala actors library is being deprecated in favor of Akka. So this answer won't be helpful very long (though the other actors library will continue to be available for a while--and since it's open source potentially forever if people want to maintain it).

Anyway, the react method is defined in scala.actors.Actor . Simply fail to import it, or hide it with your own. Your own what ?

Well, the method just takes a PartialFunction[Any,Unit] . So, your should also:

def react(pf: PartialFunction[Any,Unit]): Nothing = { /*how?;*/ Actor.react(/*what?*/) }

You really only have access to the partial function, and you have to defer to Actor.react to do what you want. So you need to wrap pf in another PartialFunction that performs your logging. So you can

val qf = new PartialFunction[Any,Unit] {
  def isDefinedAt(a: Any) = pf.isDefinedAt(a)
  def apply(a: Any): Unit = {
    log(a)  // Maybe add more logic to know what a is
    pf(a)
  }
}

If you want to see messages that come in and get examined but are not actually consumed, you could do more with isDefinedAt also.

So, obviously enough, I hope, /*how?*/ is the above to define (create) qf , and /*what?*/ is just qf .

If you want to know whether a is a case class, the answer is that you cannot (by design). A case class is just syntactic sugar on top of ordinary Scala features; it's just there to save you typing. See, for instance, this question .

However, you can get pretty close by pattern matching for Product and checking whether it has a copy method:

case class M(i: Int)
val a: Any = M(5)

scala> a match {
  case p: Product if p.getClass.getMethods.exists(_.getName=="copy") => println("Yes")
  case _ => println("No")
}
Yes

If you really want to get fancy, check if copy has the same number and type of parameters as the constructor.

//Following is a code for a logReact Method that does the same thing as react but also logs the message received hope this works for you
import scala.actors.Actor;
import scala.actors.Actor._

trait ActorLogging extends Actor {
    def logReact(handler: PartialFunction[Any, Unit]): Nothing = {
        val handler2: PartialFunction[Any, Unit] = {
            case x =>
                println("Inside Logs -- with message recieved  -- " + x.toString);
                handler.apply(x);
        }
        super.react(handler2)
    }
}

class sumAct extends Actor with ActorLogging {
    def act() {
        loop {
            logReact {
                case a: Int =>
                    println("Inside actor Sum Act Received the message -- " + a)
                    exit;
            }
        }
    }
}

object ActorLog {
    def main(args: Array[String]): Unit = {
        var s: sumAct = new sumAct;
        s.start();
        s ! 1.toInt;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM