/* CS:2820 Object Oriented Software Development Spring 2015 The University of Iowa Instructor: Cesare Tinelli */ /* Scala examples seen in class */ /* Actors */ // Up to Scala 2.9 actors were defined in the scala.actors library // That library is still there in later versions of Scala // but it is now ***deprecated*** import scala.actors._ // *** do not use this *** // The new actors library is the akka library. import akka.actor._ // use this instead class Ping(var c: Int, pong: ActorRef) extends Actor { require(c > 0) var count = c // every subclass of Actor should implement method // 'receive' which defines the actor's main behavior // 'receive' should be a "partial function" defined by // one of more case statements like those in a match // each case processes messages that match the pattern def receive = { case "start" => count = count - 1 // send asynchronous message to actor pong pong ! "ping!" println("ping sent") case "pong!" => Thread.sleep(1000) // used here just to slow down the interaction count = count - 1 if (count <= 0) { sender ! "stop" println("ping stopped") // tell the Actor system that you are ready to be permanently stopped context.stop(self) } else { sender ! "ping!" println("ping sent") } } } class Pong extends Actor { def receive = { case "ping!" => Thread.sleep(1000) sender ! "pong!" println("pong sent") case "stop" => println("pong stopped") context.stop(self) } } object PingPongSystem{ // creates and actor system called PingPongSystem val system = ActorSystem("PingPongSystem") // creates an actor of class Pong with name pongActor val pong = system.actorOf(Props[Pong], name = "pongActor") // creates an actor of class Ping val ping = system.actorOf(Props(new Ping(10, pong)), name = "pingActor") // starts the action def go = ping ! "start" } PingPongSystem.go // message sent to an actor can be objects of any type // but they must be immutable objects class EchoActor extends Actor { def receive = { case msg => { Thread.sleep(2000) println println("Received message: " + msg) } } } val echoSystem = ActorSystem("EchoSystem") val a = echoSystem.actorOf(Props[EchoActor], name = "echoActor") // any immutable object can be used as a message a ! "hi there" a ! 15 a ! (1, "abc") a ! 1::2::3::Nil // this actor responds only integer messages, // any non-integer messages are silently discarded class IntActor extends Actor { def receive = { case x: Int => // I only want Ints Thread.sleep(2000) println println("Got an Int: " + x) } } val i = echoSystem.actorOf(Props[IntActor], name = "intActor") i ! 15 i ! (1, "abc") // discarded i ! 1::2::3::Nil // discarded i ! 9 // case classes are a convenient way to create records // see Chap 16 of Scala book case class User(name: String) case class Subscribe(user: User) case class Unsubscribe(user: User) case class Post(msg: String) case class UserPost(user: User, post: Post) // there is not need to use 'new' to create an instance // o f a case class val user1 = User("Jane") val user2 = User("Mike") val request1 = Subscribe(user1) // pattern matching can be used to extract values // from the field of a case class instance val User(n1) = user1 val Subscribe(User(n2)) = request1 // this actor implements a chat room, responding to messages // that are intances of the case classes above class ChatRoom extends Actor { def receive = { case Subscribe(User(n)) => { println("I'm adding user " + n) Thread.sleep(4000) println("User " + n + " added") } case Unsubscribe(User(n)) => { println("I'm removing user " + n) Thread.sleep(4000) println("User " + n + " removed") } case UserPost(User(n), Post(c)) => { println("I'm posting " + n + "'s post: " + c) Thread.sleep(4000) println("Done posting " + n + "'s post") } } } } val chatSystem = ActorSystem("ChatSystem") val chatRoom1 = echoSystem.actorOf(Props[ChatRoom], name = "chatRoom") chatRoom1 ! Subscribe(user1) chatRoom1 ! Subscribe(user2) chatRoom1 ! Unsubscribe(user2) chatRoom1 ! UserPost(user1, Post("Hi all")) case class QuoteRequest() case class QuoteResponse(r: String) class QuoteActor extends Actor { val quotes = List( "To succeed in life, you need two things: ignorance and confidence.", "The secret of getting ahead is getting started.", "Get your facts first, then you can distort them as you please.", "Age is an issue of mind over matter. If you don't mind, it doesn't matter.", "The lack of money is the root of all evil.", "If you tell the truth, you don't have to remember anything.", "Giving up smoking is the easiest thing in the world. I know because I've done it thousands of times.", "Don't go around saying the world owes you a living. The world owes you nothing. It was here first.", "Facts are stubborn, but statistics are more pliable.", "All generalizations are false, including this one" ) val n = quotes.length val max_requests = 2 var requests = 1 def backToWork = { Thread.sleep(6000) } def receive = { case QuoteRequest => import util.Random // choose a quote randomly from the list and // construct a response with it val i = Random.nextInt(n) val quoteResponse = QuoteResponse(quotes(i)) println println(quoteResponse) // respond to up to max_requests consecutive requests, // then, reset limit counter and go back to work if (requests == max_requests) { requests = 1 backToWork } else { requests = requests + 1 } } } val quoteActorSystem = ActorSystem("QuoteSystem") val qa = quoteActorSystem.actorOf(Props[QuoteActor]) //send a message to the Teacher Actor qa ! QuoteRequest //Shut down the quote actor system. quoteActorSystem.shutdown()