-
-
Save FlatMapIO/fb78286f911071f838e0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; An (imaginary) actor macro takes an initial state and callback fns. | |
;; (actor {} (fn1 [state message]) (fn2 [state message) ...) | |
;; The most obvious callback fn is (receive [state message) that is called when a | |
;; message is consumed from the agents mailbox. receive is called with the old state | |
;; and the message as parameters -- it returns the new state. | |
;; sender is bound to the senders pid. | |
;; other callbacks are stuff broken link detection etc. | |
;; (spawn) creates a lightweight actor process, also has remote-actor semantics | |
;; (tell) is used to send messages to an spawned actor's pid. | |
(def hello-actor | |
(actor {:world-actor | |
(spawn | |
(actor {} | |
(receive [state [message-type word :as message]] | |
(condp = message-type | |
:hello (do | |
(tell sender (str (.toUpperCase word) "world!")) | |
state) | |
(unhandled message)))))} | |
(receive [state [message-type word]] | |
(condp = message-type | |
:start (do | |
(tell (:world-actor state) [:hello "hello"]) | |
state) | |
(do | |
(println (str "Received message:" word)) | |
(shutdown))))) | |
(let [pid (spawn hello-actor)] | |
(tell pid [:start])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns cljakka.vision | |
(:import [akka.actor CljActor ActorSystem Props])) | |
;; I want to be able to create a class based on an "Actor" interface. | |
;; It's important that both the class and object can be defined and created | |
;; on the fly in the repl. | |
(defrecord hello-actor [world-actor] | |
CljActor | |
;; In idiomatic Clojure, I don't want to create a Class for each message, | |
;; instead I want (like in Erlang) all messages to be a basic collection | |
;; (like vector) and switch (match) on a keyword (atom) on one of the positions. | |
(onReceice [this [message-type word :as message]] | |
(condp = message-type | |
:start (.tell world-actor [:hello "hello"]) | |
(do ;; else case | |
(println (str "Received message:" word)) | |
(-> this .getContext .getSystem .shutdown))))) | |
(defrecord world-actor [] | |
CljActor | |
(onReceive [this [message-type word :as message]] | |
(cond = message-type | |
:hello (.tell (.getSender this) | |
[(str (.toUpperCase word) "world!")]) | |
;; else case | |
(.unhandled this message)))) | |
;; The defrecords above creates a new class that implements the new interface, | |
;; it is then instanciated like (world-actor.) | |
;; There are other (niftier) ways in Clojure to create an object directly | |
;; on an interface directly without needing to define the class first | |
;; (with proxy and reify) - this create anonymous classes and is powerful. | |
;; However, this totally screws up Akka's factories, but I wants it! :) | |
(def world-actor2 | |
(reify CljActor | |
(onRecieve [this message] | |
(.unhandled this message)))) | |
;; Now, it is possible to generate a "proper" class like in the java examples. | |
;; You can do this in clojure with (gen-class), but that requires a compile | |
;; step. Which is for a clojure developer appaling. We live and | |
;; breathe in the REPL. See how awful it becomes; | |
;; https://github.com/martintrojer/clojak/blob/master/src/clojak/core.clj | |
(defn -main [& args] | |
(let [system (ActorSystem.) | |
;; here system.actorOf takes an object! | |
world-act (.actorOf system (world-actor.)) | |
;; or perhaps the Props ctor takes an object? | |
world-act2 (.actorOf system (Props. (world-actor.))) | |
hello-act (.actorOf system (Props. (hello-actor. world-act))) | |
;; or Props takes the class, but how do create it with arguments? | |
hello-act2 (.actorOf system (Props. hello-actor))] | |
(.tell hello-act [:start]))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package akka.tutorial.first.java; | |
import akka.actor.ActorRef; | |
import akka.actor.UntypedActor; | |
import akka.actor.UntypedActorFactory; | |
import akka.actor.ActorSystem; | |
import akka.actor.Props; | |
public class Hello { | |
public static void main(String[] args) | |
{ | |
final ActorSystem system = ActorSystem.create("hellokernel"); | |
Props props = new Props().withCreator(new UntypedActorFactory() { | |
public UntypedActor create() { | |
return new HelloActor(); | |
} | |
}); | |
ActorRef helloActor = system.actorOf(props); | |
helloActor.tell("start"); | |
} | |
public static class HelloActor extends UntypedActor { | |
final ActorRef worldActor = | |
getContext().actorOf(new Props(new UntypedActorFactory() { | |
public UntypedActor create() { | |
return new WorldActor(); | |
} | |
})); | |
public void onReceive(Object message) { | |
if (message instanceof String) { | |
String strmess = (String) message; | |
if (strmess == "start") | |
worldActor.tell("Hello", getSelf()); | |
else | |
System.out.println("Received message '%s'".format((String)message)); | |
} | |
else unhandled(message); | |
} | |
} | |
public static class WorldActor extends UntypedActor { | |
public void onReceive(Object message) { | |
if (message instanceof String) | |
getSender().tell(((String)message).toUpperCase() + " world!"); | |
else unhandled(message); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package sample.hello | |
import akka.actor.{ ActorSystem, Actor, Props } | |
case object Start | |
object Main { | |
def main(args: Array[String]): Unit = { | |
val system = ActorSystem() | |
system.actorOf(Props[HelloActor]) ! Start | |
} | |
} | |
class HelloActor extends Actor { | |
val worldActor = context.actorOf(Props[WorldActor]) | |
def receive = { | |
case Start ⇒ worldActor ! "Hello" | |
case s: String ⇒ | |
println("Received message: %s".format(s)) | |
context.system.shutdown() | |
} | |
} | |
class WorldActor extends Actor { | |
def receive = { | |
case s: String ⇒ sender ! s.toUpperCase + " world!" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment