From 651f699893e5634a7edaf606527e31c644b7e876 Mon Sep 17 00:00:00 2001 From: Roland Date: Wed, 24 Apr 2013 22:46:39 +0200 Subject: [PATCH] add akka.Main and use that to add Hello World docs - akka.Main will start an ActorSystem and one actor; when that actor terminates the system is shut down - HelloWorld sample with two actors --- akka-actor/src/main/scala/akka/Main.scala | 42 ++++++++++++++++ akka-docs/rst/intro/getting-started.rst | 2 + .../rst/intro/{index.rst => index-java.rst} | 1 + akka-docs/rst/intro/index-scala.rst | 13 +++++ akka-docs/rst/java.rst | 2 +- .../java/code/docs/actor/japi/Greeter.java | 26 ++++++++++ .../java/code/docs/actor/japi/HelloWorld.java | 31 ++++++++++++ akka-docs/rst/java/hello-world.rst | 43 ++++++++++++++++ akka-docs/rst/scala.rst | 2 +- .../scala/code/docs/actor/IntroDocSpec.scala | 50 +++++++++++++++++++ akka-docs/rst/scala/hello-world.rst | 44 ++++++++++++++++ 11 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 akka-actor/src/main/scala/akka/Main.scala rename akka-docs/rst/intro/{index.rst => index-java.rst} (86%) create mode 100644 akka-docs/rst/intro/index-scala.rst create mode 100644 akka-docs/rst/java/code/docs/actor/japi/Greeter.java create mode 100644 akka-docs/rst/java/code/docs/actor/japi/HelloWorld.java create mode 100644 akka-docs/rst/java/hello-world.rst create mode 100644 akka-docs/rst/scala/code/docs/actor/IntroDocSpec.scala create mode 100644 akka-docs/rst/scala/hello-world.rst diff --git a/akka-actor/src/main/scala/akka/Main.scala b/akka-actor/src/main/scala/akka/Main.scala new file mode 100644 index 0000000000..0a9d56dce2 --- /dev/null +++ b/akka-actor/src/main/scala/akka/Main.scala @@ -0,0 +1,42 @@ +/** + * Copyright (C) 2009-2013 Typesafe Inc. + */ + +package akka + +import akka.actor.ActorSystem +import akka.actor.ExtendedActorSystem +import akka.actor.Actor +import akka.actor.Terminated +import akka.actor.ActorLogging +import akka.actor.Props +import akka.actor.ActorRef +import scala.util.control.NonFatal + +object Main { + + def main(args: Array[String]): Unit = { + if (args.length != 1) { + println("you need to provide exactly one argument: the class of the application supervisor actor") + } else { + val system = ActorSystem("Main") + try { + val appClass = system.asInstanceOf[ExtendedActorSystem].dynamicAccess.getClassFor[Actor](args(0)).get + val app = system.actorOf(Props(appClass), "app") + val terminator = system.actorOf(Props(classOf[Terminator], app), "app-terminator") + } catch { + case NonFatal(e) ⇒ system.shutdown(); throw e + } + } + } + + class Terminator(app: ActorRef) extends Actor with ActorLogging { + context watch app + def receive = { + case Terminated(_) ⇒ + log.info("application supervisor has terminated, shutting down") + context.system.shutdown() + } + } + +} diff --git a/akka-docs/rst/intro/getting-started.rst b/akka-docs/rst/intro/getting-started.rst index 777bfb370c..97d47da2ec 100644 --- a/akka-docs/rst/intro/getting-started.rst +++ b/akka-docs/rst/intro/getting-started.rst @@ -115,6 +115,8 @@ directory. More information is available in the documentation of the :ref:`microkernel-scala` / :ref:`microkernel-java`. +.. _build-tool: + Using a build tool ------------------ diff --git a/akka-docs/rst/intro/index.rst b/akka-docs/rst/intro/index-java.rst similarity index 86% rename from akka-docs/rst/intro/index.rst rename to akka-docs/rst/intro/index-java.rst index eaca026e8f..a826e59bb2 100644 --- a/akka-docs/rst/intro/index.rst +++ b/akka-docs/rst/intro/index-java.rst @@ -7,6 +7,7 @@ Introduction what-is-akka why-akka getting-started + ../java/hello-world deployment-scenarios use-cases diff --git a/akka-docs/rst/intro/index-scala.rst b/akka-docs/rst/intro/index-scala.rst new file mode 100644 index 0000000000..7cf8450db1 --- /dev/null +++ b/akka-docs/rst/intro/index-scala.rst @@ -0,0 +1,13 @@ +Introduction +============ + +.. toctree:: + :maxdepth: 2 + + what-is-akka + why-akka + getting-started + ../scala/hello-world + deployment-scenarios + use-cases + diff --git a/akka-docs/rst/java.rst b/akka-docs/rst/java.rst index 30d5edce48..46dca46987 100644 --- a/akka-docs/rst/java.rst +++ b/akka-docs/rst/java.rst @@ -6,7 +6,7 @@ Java Documentation .. toctree:: :maxdepth: 2 - intro/index + intro/index-java general/index java/index-actors java/index-futures diff --git a/akka-docs/rst/java/code/docs/actor/japi/Greeter.java b/akka-docs/rst/java/code/docs/actor/japi/Greeter.java new file mode 100644 index 0000000000..239b615a05 --- /dev/null +++ b/akka-docs/rst/java/code/docs/actor/japi/Greeter.java @@ -0,0 +1,26 @@ +/** + * Copyright (C) 2009-2013 Typesafe Inc. + */ + +package docs.actor.japi; + +import akka.actor.UntypedActor; +import java.io.Serializable; + +//#greeter +public class Greeter extends UntypedActor { + + public static enum Msg { + GREET, DONE; + } + + @Override + public void onReceive(Object msg) { + if (msg == Msg.GREET) { + System.out.println("Hello World!"); + getSender().tell(Msg.DONE, getSelf()); + } else unhandled(msg); + } + +} +//#greeter diff --git a/akka-docs/rst/java/code/docs/actor/japi/HelloWorld.java b/akka-docs/rst/java/code/docs/actor/japi/HelloWorld.java new file mode 100644 index 0000000000..396b1881b3 --- /dev/null +++ b/akka-docs/rst/java/code/docs/actor/japi/HelloWorld.java @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2009-2013 Typesafe Inc. + */ + +package docs.actor.japi; + +//#hello-world +import akka.actor.Props; +import akka.actor.UntypedActor; +import akka.actor.ActorRef; + +public class HelloWorld extends UntypedActor { + + @Override + public void preStart() { + // create the greeter actor + final ActorRef greeter = + getContext().actorOf(Props.create(Greeter.class), "greeter"); + // tell it to perform the greeting + greeter.tell(Greeter.Msg.GREET, getSelf()); + } + + @Override + public void onReceive(Object msg) { + if (msg == Greeter.Msg.DONE) { + // when the greeter is done, stop this actor and with it the application + getContext().stop(getSelf()); + } else unhandled(msg); + } +} +//#hello-world \ No newline at end of file diff --git a/akka-docs/rst/java/hello-world.rst b/akka-docs/rst/java/hello-world.rst new file mode 100644 index 0000000000..5ba984e1a2 --- /dev/null +++ b/akka-docs/rst/java/hello-world.rst @@ -0,0 +1,43 @@ +########################## +The Obligatory Hello World +########################## + +Since every programming paradigm needs to solve the tough problem of printing a +well-known greeting to the console we’ll introduce you to the actor-based +version. + +.. includecode:: ../java/code/docs/actor/japi/HelloWorld.java#hello-world + +The ``HelloWorld`` actor is the application’s “main” class; when it terminates +the application will shut down—more on that later. The main business logic +happens in the :meth:`preStart` method, where a ``Greeter`` actor is created +and instructed to issue that greeting we crave for. When the greeter is done it +will tell us so by sending back a message, and when that message has been +received it will be passed into the :meth:`onReceive` method where we can +conclude the demonstration by stopping the ``HelloWorld`` actor. You will be +very curious to see how the ``Greeter`` actor performs the actual task: + +.. includecode:: ../java/code/docs/actor/japi/Greeter.java#greeter + +This is extremely simple now: after its creation this actor will not do +anything until someone sends it a message, and if that happens to be an +invitation to greet the world then the ``Greeter`` complies and informs the +requester that the deed has been done. + +As a Java developer you will probably want to tell us that there is no +``static public void main(...)`` anywhere in these classes, so how do we run +this program? The answer is that the appropriate :meth:`main` method is +implemented in the generic launcher class :class:`akka.Main` which expects only +one command line argument: the class name of the application’s main actor. This +main method will then create the infrastructure needed for running the actors, +start the given main actor and arrange for the whole application to shut down +once the main actor terminates. Thus you will be able to run the above code +with a command similar to the following:: + + java -classpath akka.Main com.example.HelloWorld + +This conveniently assumes placement of the above class definitions in package +``com.example`` and it further assumes that you have the required JAR files for +``scala-library`` and ``akka-actor`` available. The easiest would be to manage +these dependencies with a build tool, see :ref:`build-tool`. + diff --git a/akka-docs/rst/scala.rst b/akka-docs/rst/scala.rst index db65cea5af..473b199f76 100644 --- a/akka-docs/rst/scala.rst +++ b/akka-docs/rst/scala.rst @@ -6,7 +6,7 @@ Scala Documentation .. toctree:: :maxdepth: 2 - intro/index + intro/index-scala general/index scala/index-actors scala/index-futures diff --git a/akka-docs/rst/scala/code/docs/actor/IntroDocSpec.scala b/akka-docs/rst/scala/code/docs/actor/IntroDocSpec.scala new file mode 100644 index 0000000000..42ca19e51d --- /dev/null +++ b/akka-docs/rst/scala/code/docs/actor/IntroDocSpec.scala @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2009-2013 Typesafe Inc. + */ + +package docs.actor + +import akka.testkit.AkkaSpec + +//#hello-world +import akka.actor.Actor +import akka.actor.Props + +class HelloWorld extends Actor { + + override def preStart(): Unit = { + // create the greeter actor + val greeter = context.actorOf(Props[Greeter], "greeter") + // tell it to perform the greeting + greeter ! Greeter.Greet + } + + def receive = { + // when the greeter is done, stop this actor and with it the application + case Greeter.Done ⇒ context.stop(self) + } +} +//#hello-world + +//#greeter +object Greeter { + case object Greet + case object Done +} + +class Greeter extends Actor { + def receive = { + case Greeter.Greet ⇒ + println("Hello World!") + sender ! Greeter.Done + } +} +//#greeter + +class IntroDocSpec extends AkkaSpec { + + "demonstrate HelloWorld" in { + expectTerminated(watch(system.actorOf(Props[HelloWorld]))) + } + +} \ No newline at end of file diff --git a/akka-docs/rst/scala/hello-world.rst b/akka-docs/rst/scala/hello-world.rst new file mode 100644 index 0000000000..ad79cbe505 --- /dev/null +++ b/akka-docs/rst/scala/hello-world.rst @@ -0,0 +1,44 @@ +########################## +The Obligatory Hello World +########################## + +Since every programming paradigm needs to solve the tough problem of printing a +well-known greeting to the console we’ll introduce you to the actor-based +version. + +.. includecode:: ../scala/code/docs/actor/IntroDocSpec.scala#hello-world + +The ``HelloWorld`` actor is the application’s “main” class; when it terminates +the application will shut down—more on that later. The main business logic +happens in the :meth:`preStart` method, where a ``Greeter`` actor is created +and instructed to issue that greeting we crave for. When the greeter is done it +will tell us so by sending back a message, and when that message has been +received it will be passed into the behavior described by the :meth:`receive` +method where we can conclude the demonstration by stopping the ``HelloWorld`` +actor. You will be very curious to see how the ``Greeter`` actor performs the +actual task: + +.. includecode:: ../scala/code/docs/actor/IntroDocSpec.scala#greeter + +This is extremely simple now: after its creation this actor will not do +anything until someone sends it a message, and if that happens to be an +invitation to greet the world then the ``Greeter`` complies and informs the +requester that the deed has been done. + +As a Scala developer you will probably want to tell us that there is no +``main(Array[String])`` method anywhere in these classes, so how do we run this +program? The answer is that the appropriate :meth:`main` method is implemented +in the generic launcher class :class:`akka.Main` which expects only one command +line argument: the class name of the application’s main actor. This main method +will then create the infrastructure needed for running the actors, start the +given main actor and arrange for the whole application to shut down once the +main actor terminates. Thus you will be able to run the above code with a +command similar to the following:: + + java -classpath akka.Main com.example.HelloWorld + +This conveniently assumes placement of the above class definitions in package +``com.example`` and it further assumes that you have the required JAR files for +``scala-library`` and ``akka-actor`` available. The easiest would be to manage +these dependencies with a build tool, see :ref:`build-tool`. +