├── .gitignore
├── source-code
└── learn-akka
│ ├── project
│ ├── build.properties
│ └── plugins.sbt
│ ├── src
│ ├── main
│ │ ├── resources
│ │ │ ├── error-page.html
│ │ │ └── application.conf
│ │ └── scala
│ │ │ └── com
│ │ │ └── allaboutscala
│ │ │ └── learn
│ │ │ └── akka
│ │ │ ├── dispatchers
│ │ │ ├── Tutorial_02_AkkaLookupDispatcher.scala
│ │ │ ├── Tutorial_01_AkkaDefaultDispatcher.scala
│ │ │ ├── Tutorial_05_PinnedDispatcher.scala
│ │ │ ├── Tutorial_04_AkkaResizableThreadPool.scala
│ │ │ └── Tutorial_03_AkkaFixedThreadPoolDispatcher.scala
│ │ │ ├── http
│ │ │ ├── jsonsupport
│ │ │ │ └── JsonSupport.scala
│ │ │ ├── routes
│ │ │ │ ├── ServerVersionRoute.scala
│ │ │ │ └── DonutRoute.scala
│ │ │ └── AkkaHttpServer.scala
│ │ │ ├── actors
│ │ │ ├── Tutorial_01_ActorSystem_Introduction.scala
│ │ │ ├── Tutorial_02_Tell_Pattern.scala
│ │ │ ├── Tutorial_06_Actor_Lookup.scala
│ │ │ ├── Tutorial_07_Child_actors.scala
│ │ │ ├── Tutorial_04_Ask_Pattern_MapTo.scala
│ │ │ ├── Tutorial_03_Ask_Pattern.scala
│ │ │ ├── Tutorial_05_Ask_Pattern_PipeTo.scala
│ │ │ ├── Tutorial_08_Actor_Lifecycle.scala
│ │ │ ├── Tutorial_09_Actor_PoisonPill.scala
│ │ │ └── Tutorial_10_Error_Kernel_Supervision.scala
│ │ │ ├── fsm
│ │ │ ├── Tutorial_01_AkkaFSMBecome.scala
│ │ │ ├── Tutorial_11_AkkaScheduler.scala
│ │ │ ├── Tutorial_02_AkkaFSMUnbecome.scala
│ │ │ ├── Tutorial_04_AkkaFSM.scala
│ │ │ ├── Tutorial_03_AkkaFSMProtocol.scala
│ │ │ ├── Tutorial_05_AkkaFSM_PartTwo.scala
│ │ │ ├── Tutorial_06_AkkaFSM_PartThree.scala
│ │ │ ├── Tutorial_07_AkkaFSM_PartFour.scala
│ │ │ ├── Tutorial_08_AkkaFSM_PartFive.scala
│ │ │ └── Tutorial_09_AkkaFSM_PartSix.scala
│ │ │ ├── client
│ │ │ └── AkkaHTTPClient.scala
│ │ │ └── routers
│ │ │ ├── Tutorial_04_BroadcastPoolRouter.scala
│ │ │ ├── Tutorial_01_RoundRobinPoolRouter.scala
│ │ │ ├── Tutorial_03_TailChoppingPool.scala
│ │ │ └── Tutorial_02_ScatterGatherFirstCompletedPoolRouter.scala
│ └── test
│ │ └── scala
│ │ └── com
│ │ └── allaboutscala
│ │ └── learn
│ │ └── akka
│ │ ├── http
│ │ ├── CreateDonutTest.scala
│ │ └── DonutQueryParametersTest.scala
│ │ └── fsm
│ │ ├── DonutBakingActorFSMTests.scala
│ │ └── DonutInfoActorTests.scala
│ ├── .gitignore
│ └── build.sbt
├── README.md
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | *.log
3 |
--------------------------------------------------------------------------------
/source-code/learn-akka/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version = 0.13.8
--------------------------------------------------------------------------------
/source-code/learn-akka/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | logLevel := Level.Warn
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/resources/error-page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Error Page
4 |
5 |
6 | This is some default error page
7 |
8 |
--------------------------------------------------------------------------------
/source-code/learn-akka/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | *.log
3 |
4 | # sbt specific
5 | .cache
6 | .history
7 | .lib/
8 | dist/*
9 | target/
10 | lib_managed/
11 | src_managed/
12 | project/boot/
13 | project/plugins/project/
14 |
15 | # Scala-IDE specific
16 | .scala_dependencies
17 | .worksheet
18 | .idea
19 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | fixed-thread-pool {
2 | type = Dispatcher
3 | executor = "thread-pool-executor"
4 | thread-pool-executor {
5 | fixed-pool-size = 10
6 | }
7 | throughput = 2
8 | }
9 |
10 | resizable-thread-pool {
11 | type = Dispatcher
12 | executor = "thread-pool-executor"
13 | thread-pool-executor {
14 | core-pool-size-min = 5
15 | core-pool-size-factor = 2.0
16 | core-pool-size-max = 20
17 | }
18 | throughput = 5
19 | }
20 |
21 | pinned-thread-pool {
22 | executor = "thread-pool-executor"
23 | type = PinnedDispatcher
24 | }
--------------------------------------------------------------------------------
/source-code/learn-akka/build.sbt:
--------------------------------------------------------------------------------
1 | name := "learn-akka"
2 |
3 | version := "1.0"
4 |
5 | scalaVersion := "2.12.4"
6 |
7 | libraryDependencies ++= Seq(
8 | "com.typesafe.akka" %% "akka-actor" % "2.5.19",
9 | "com.typesafe.akka" %% "akka-stream" % "2.5.19",
10 | "com.typesafe.akka" %% "akka-http" % "10.1.6",
11 | "com.typesafe.akka" %% "akka-http-spray-json" % "10.1.6",
12 | "com.typesafe.akka" %% "akka-http-testkit" % "10.1.6" % "test",
13 | "com.typesafe.akka" %% "akka-testkit" % "2.5.19" % Test,
14 | "com.typesafe.scala-logging" %% "scala-logging" % "3.7.2",
15 | "ch.qos.logback" % "logback-classic" % "1.2.3",
16 | "org.scalatest" %% "scalatest" % "3.0.1" % Test
17 | )
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/dispatchers/Tutorial_02_AkkaLookupDispatcher.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.dispatchers
2 |
3 | import akka.actor.ActorSystem
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_02_AkkaLookupDispatcher extends App {
27 |
28 | val system = ActorSystem("DonutStoreActorSystem")
29 | implicit val executionContext = system.dispatchers.lookup("fixed-thread-pool")
30 | system.terminate()
31 | }
32 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/http/jsonsupport/JsonSupport.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.http.jsonsupport
2 |
3 | import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
4 | import spray.json.DefaultJsonProtocol
5 |
6 | /**
7 | * Created by Nadim Bahadoor on 28/06/2016.
8 | *
9 | * Tutorial: Learn How To Use Akka HTTP
10 | *
11 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
12 | *
13 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
14 | *
15 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
16 | * use this file except in compliance with the License. You may obtain a copy of
17 | * the License at
18 | *
19 | * [http://www.apache.org/licenses/LICENSE-2.0]
20 | *
21 | * Unless required by applicable law or agreed to in writing, software
22 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
23 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
24 | * License for the specific language governing permissions and limitations under
25 | * the License.
26 | */
27 |
28 | final case class AkkaHttpRestServer(app: String, version: String)
29 | final case class Donut(name: String, price: Double)
30 | final case class Donuts(donuts: Seq[Donut])
31 |
32 | trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
33 |
34 | import spray.json._
35 | implicit val printer = PrettyPrinter
36 |
37 | implicit val serverFormat = jsonFormat2(AkkaHttpRestServer)
38 | implicit val donutFormat = jsonFormat2(Donut)
39 | implicit val donutsJsonFormat = jsonFormat1(Donuts)
40 | }
41 |
42 |
43 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/actors/Tutorial_01_ActorSystem_Introduction.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.actors
2 |
3 | import akka.actor.ActorSystem
4 |
5 | import scala.util.{Failure, Success}
6 | import scala.concurrent.ExecutionContext.Implicits.global
7 |
8 | /**
9 | * Created by Nadim Bahadoor on 28/06/2016.
10 | *
11 | * Tutorial: Learn How To Use Akka
12 | *
13 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
14 | *
15 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
16 | *
17 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
18 | * use this file except in compliance with the License. You may obtain a copy of
19 | * the License at
20 | *
21 | * [http://www.apache.org/licenses/LICENSE-2.0]
22 | *
23 | * Unless required by applicable law or agreed to in writing, software
24 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
25 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26 | * License for the specific language governing permissions and limitations under
27 | * the License.
28 | */
29 | object Tutorial_01_ActorSystem_Introduction extends App {
30 |
31 | println("Step 1: create an actor system")
32 | val system = ActorSystem("DonutStoreActorSystem")
33 |
34 |
35 |
36 | println("\nStep 2: close the actor system")
37 | val isTerminated = system.terminate()
38 |
39 |
40 |
41 | println("\nStep 3: Check the status of the actor system")
42 | isTerminated.onComplete {
43 | case Success(result) => println("Successfully terminated actor system")
44 | case Failure(e) => println("Failed to terminate actor system")
45 | }
46 | Thread.sleep(5000)
47 | }
48 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/test/scala/com/allaboutscala/learn/akka/http/CreateDonutTest.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.http
2 |
3 | import akka.http.scaladsl.model.{HttpEntity, HttpMethods, HttpRequest, MediaTypes}
4 | import akka.http.scaladsl.testkit.ScalatestRouteTest
5 | import akka.util.ByteString
6 | import com.allaboutscala.learn.akka.http.routes.DonutRoutes
7 | import org.scalatest.{Matchers, WordSpec}
8 |
9 | /**
10 | * Created by Nadim Bahadoor on 28/06/2016.
11 | *
12 | * Tutorial: Learn How To Use Akka HTTP
13 | *
14 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
15 | *
16 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
17 | *
18 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
19 | * use this file except in compliance with the License. You may obtain a copy of
20 | * the License at
21 | *
22 | * [http://www.apache.org/licenses/LICENSE-2.0]
23 | *
24 | * Unless required by applicable law or agreed to in writing, software
25 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
26 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
27 | * License for the specific language governing permissions and limitations under
28 | * the License.
29 | */
30 | class CreateDonutTest
31 | extends WordSpec
32 | with Matchers
33 | with ScalatestRouteTest {
34 |
35 | val donutRoutes = new DonutRoutes().route()
36 |
37 | "Donut API" should {
38 | "Create a valid Donut when posting JSON to /create-donut path" in {
39 | val jsonDonutInput = ByteString("""{"name":"plain donut", "price":1.50}""")
40 | val httpPostCreateDonut = HttpRequest(
41 | uri = "http://localhost:8080/create-donut",
42 | method = HttpMethods.POST,
43 | entity = HttpEntity(MediaTypes.`application/json`, jsonDonutInput))
44 |
45 | httpPostCreateDonut ~> donutRoutes ~> check {
46 | status.isSuccess() shouldEqual true
47 | status.intValue() shouldEqual 201
48 | status.reason shouldEqual "Created"
49 | }
50 | }
51 | }
52 |
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/actors/Tutorial_02_Tell_Pattern.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.actors
2 |
3 | import akka.actor.{ActorSystem, Props, Actor, ActorLogging}
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_02_Tell_Pattern extends App {
27 |
28 | println("Step 1: Create an actor system")
29 | val system = ActorSystem("DonutStoreActorSystem")
30 |
31 |
32 |
33 | println("\nStep 4: Create DonutInfoActor")
34 | val donutInfoActor = system.actorOf(Props[DonutInfoActor], name = "DonutInfoActor")
35 |
36 |
37 |
38 | println("\nStep 5: Akka Tell Pattern")
39 | import DonutStoreProtocol._
40 | donutInfoActor ! Info("vanilla")
41 |
42 |
43 |
44 | println("\nStep 6: close the actor system")
45 | val isTerminated = system.terminate()
46 |
47 |
48 |
49 | println("\nStep 2: Define the message passing protocol for our DonutStoreActor")
50 | object DonutStoreProtocol {
51 | case class Info(name: String)
52 | }
53 |
54 |
55 |
56 | println("\nStep 3: Define DonutInfoActor")
57 | class DonutInfoActor extends Actor with ActorLogging {
58 |
59 | import Tutorial_02_Tell_Pattern.DonutStoreProtocol._
60 |
61 | def receive = {
62 | case Info(name) =>
63 | log.info(s"Found $name donut")
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/http/routes/ServerVersionRoute.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.http.routes
2 |
3 | import akka.http.scaladsl.model.{ContentTypes, HttpEntity}
4 | import akka.http.scaladsl.server.Directives._
5 | import akka.http.scaladsl.server.Route
6 | import com.allaboutscala.learn.akka.http.jsonsupport.{JsonSupport, AkkaHttpRestServer}
7 |
8 | /**
9 | * Created by Nadim Bahadoor on 28/06/2016.
10 | *
11 | * Tutorial: Learn How To Use Akka HTTP
12 | *
13 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
14 | *
15 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
16 | *
17 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
18 | * use this file except in compliance with the License. You may obtain a copy of
19 | * the License at
20 | *
21 | * [http://www.apache.org/licenses/LICENSE-2.0]
22 | *
23 | * Unless required by applicable law or agreed to in writing, software
24 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
25 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26 | * License for the specific language governing permissions and limitations under
27 | * the License.
28 | */
29 | class ServerVersion extends JsonSupport {
30 |
31 | def route(): Route = {
32 | path("server-version") {
33 | get {
34 | val serverVersion = "1.0.0.0"
35 | complete(HttpEntity(ContentTypes.`text/plain(UTF-8)`, serverVersion))
36 | }
37 | }
38 | }
39 |
40 |
41 |
42 | def routeAsJson(): Route = {
43 | path("server-version-json") {
44 | get {
45 | val jsonResponse =
46 | """
47 | |{
48 | | "app": "Akka HTTP REST Server",
49 | | "version": "1.0.0.0"
50 | |}
51 | """.stripMargin
52 | complete(HttpEntity(ContentTypes.`application/json`, jsonResponse))
53 | }
54 | }
55 | }
56 |
57 |
58 |
59 | def routeAsJsonEncoding(): Route = {
60 | path("server-version-json-encoding") {
61 | get {
62 | val server = AkkaHttpRestServer("Akka HTTP REST Server", "1.0.0.0")
63 | complete(server)
64 | }
65 | }
66 | }
67 | }
68 |
69 |
70 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/actors/Tutorial_06_Actor_Lookup.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.actors
2 |
3 | import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_06_Actor_Lookup extends App {
27 |
28 | println("Step 1: Create an actor system")
29 | val system = ActorSystem("DonutStoreActorSystem")
30 |
31 |
32 |
33 | println("\nStep 4: Create DonutInfoActor")
34 | val donutInfoActor = system.actorOf(Props[DonutInfoActor], name = "DonutInfoActor")
35 |
36 |
37 |
38 | println("\nStep 5: Akka Tell Pattern")
39 | import DonutStoreProtocol._
40 | donutInfoActor ! Info("vanilla")
41 |
42 |
43 |
44 | println("\nStep 6: Find Actor using actorSelection() method")
45 | system.actorSelection("/user/DonutInfoActor") ! Info("chocolate")
46 | system.actorSelection("/user/*") ! Info("vanilla and chocolate")
47 |
48 |
49 |
50 | println("\nStep 7: close the actor system")
51 | val isTerminated = system.terminate()
52 |
53 |
54 |
55 | println("\nStep 2: Define the message passing protocol for our DonutStoreActor")
56 | object DonutStoreProtocol {
57 | case class Info(name: String)
58 | }
59 |
60 |
61 | println("\nStep 3: Define DonutInfoActor")
62 | class DonutInfoActor extends Actor with ActorLogging {
63 |
64 | def receive = {
65 | case Info(name) =>
66 | log.info(s"Found $name donut")
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/dispatchers/Tutorial_01_AkkaDefaultDispatcher.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.dispatchers
2 |
3 | import akka.actor.ActorSystem
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_01_AkkaDefaultDispatcher extends App {
27 |
28 | println("Step 1: Create an actor system")
29 | val system = ActorSystem("DonutStoreActorSystem")
30 |
31 |
32 | println("\nStep 2: Akka default dispatcher config")
33 | val defaultDispatcherConfig = system.settings.config.getConfig("akka.actor.default-dispatcher")
34 | println(s"akka.actor.default-dispatcher = $defaultDispatcherConfig")
35 |
36 |
37 |
38 | println("\nStep 3: Akka default dispatcher type")
39 | val dispatcherType = defaultDispatcherConfig.getString("type")
40 | println(s"$dispatcherType")
41 |
42 |
43 |
44 | println("\nStep 4: Akka default dispatcher throughput")
45 | val dispatcherThroughput = defaultDispatcherConfig.getString("throughput")
46 | println(s"$dispatcherThroughput")
47 |
48 |
49 |
50 | println("\nStep 5: Akka default dispatcher minimum parallelism")
51 | val dispatcherParallelismMin = defaultDispatcherConfig.getInt("fork-join-executor.parallelism-min")
52 | println(s"$dispatcherParallelismMin")
53 |
54 |
55 | println("\nStep 6: Akka default dispatcher maximum parallelism")
56 | val dispatcherParallelismMax = defaultDispatcherConfig.getInt("fork-join-executor.parallelism-max")
57 | println(s"$dispatcherParallelismMax")
58 |
59 |
60 |
61 | println("\nStep 7: Close the actor system")
62 | val isTerminated = system.terminate()
63 | }
64 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/actors/Tutorial_07_Child_actors.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.actors
2 |
3 | import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_07_Child_actors extends App {
27 |
28 | println("Step 1: Create an actor system")
29 | val system = ActorSystem("DonutStoreActorSystem")
30 |
31 |
32 | println("\nStep 4: Create DonutInfoActor")
33 | val donutInfoActor = system.actorOf(Props[DonutInfoActor], name = "DonutInfoActor")
34 |
35 |
36 |
37 | println("\nStep 5: Akka Tell Pattern")
38 | import DonutStoreProtocol._
39 | donutInfoActor ! Info("vanilla")
40 |
41 | Thread.sleep(3000)
42 |
43 |
44 |
45 | println("\nStep 6: close the actor system")
46 | val isTerminated = system.terminate()
47 |
48 |
49 |
50 | println("\nStep 2: Define the message passing protocol for our DonutStoreActor")
51 | object DonutStoreProtocol {
52 | case class Info(name: String)
53 | }
54 |
55 |
56 |
57 | println("\nStep 3: Define a BakingActor and a DonutInfoActor")
58 | class BakingActor extends Actor with ActorLogging {
59 |
60 | def receive = {
61 | case Info(name) =>
62 | log.info(s"BakingActor baking $name donut")
63 | }
64 | }
65 |
66 |
67 | class DonutInfoActor extends Actor with ActorLogging {
68 |
69 | val bakingActor = context.actorOf(Props[BakingActor], name = "BakingActor")
70 |
71 | def receive = {
72 | case msg @ Info(name) =>
73 | log.info(s"Found $name donut")
74 | bakingActor forward msg
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/fsm/Tutorial_01_AkkaFSMBecome.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.fsm
2 |
3 | import akka.actor.{ActorLogging, ActorSystem, Props, Actor}
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_01_AkkaFSMBecome extends App {
27 | println("Step 1: Create ActorSystem")
28 | val system = ActorSystem("ActorStateBecome")
29 |
30 |
31 | println("\nStep 3: Create DonutBakingActor")
32 | val bakingActor = system.actorOf(Props[DonutBakingActor], "donut-baking-actor")
33 |
34 |
35 |
36 | println("\nStep 4: Send events to actor to switch states and process events")
37 | bakingActor ! "boom" // not valid
38 | Thread.sleep(2000)
39 |
40 |
41 | bakingActor ! "BakeDonut"
42 | Thread.sleep(2000)
43 |
44 |
45 | bakingActor ! "BakePlain"
46 | Thread.sleep(2000)
47 |
48 |
49 | bakingActor ! "BakeVanilla"
50 | Thread.sleep(2000)
51 |
52 |
53 | bakingActor ! "Bake Chocolate"
54 | Thread.sleep(2000)
55 |
56 |
57 | system.terminate()
58 |
59 |
60 |
61 | println("\nStep 2: Define DonutBakingActor with become() states")
62 | class DonutBakingActor extends Actor with ActorLogging {
63 | import context._
64 |
65 | def receive = {
66 | case "BakeDonut" =>
67 | log.info("Becoming BakeDonut state")
68 | become {
69 | case "BakeVanilla" =>
70 | log.info("baking vanilla")
71 |
72 | case "BakePlain" =>
73 | log.info("baking plain")
74 |
75 | case event @ _ =>
76 | log.info(s"Allowed events [BakeVanilla, BakePlain], event = $event")
77 | }
78 |
79 | case event @ _ =>
80 | log.info(s"Allowed events [BakeDonut], events = $event")
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/fsm/Tutorial_11_AkkaScheduler.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.fsm
2 |
3 | import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
4 |
5 | import scala.io.StdIn
6 |
7 |
8 | /**
9 | * Created by Nadim Bahadoor on 28/06/2016.
10 | *
11 | * Tutorial: Learn How To Use Akka
12 | *
13 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
14 | *
15 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
16 | *
17 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
18 | * use this file except in compliance with the License. You may obtain a copy of
19 | * the License at
20 | *
21 | * [http://www.apache.org/licenses/LICENSE-2.0]
22 | *
23 | * Unless required by applicable law or agreed to in writing, software
24 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
25 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26 | * License for the specific language governing permissions and limitations under
27 | * the License.
28 | */
29 | object Tutorial_11_AkkaScheduler extends App {
30 |
31 | println("Step 1. Create ActorSystem")
32 | val system = ActorSystem("ActorState")
33 |
34 |
35 |
36 | println("\nStep 3: Create DonutBakingActor")
37 | val bakingActor = system.actorOf(Props[DonutBakingActor], "donut-baking-actor")
38 |
39 |
40 |
41 | println("\nStep 4: Send events to actor to switch states and process events")
42 | bakingActor ! "BakeDonut"
43 | Thread.sleep(2000)
44 |
45 |
46 |
47 | println("\nStep 5: Using system.scheduler to send periodic events to actor")
48 | import system.dispatcher
49 | import scala.concurrent.duration._
50 |
51 | system.scheduler.schedule(1.seconds, 2.seconds) {
52 | bakingActor ! "BakeVanilla"
53 | Thread.sleep(1000)
54 | }
55 |
56 | StdIn.readLine()
57 |
58 |
59 |
60 | println("\nStep 2: Define DonutBakingActor with become() and unbecome() states")
61 | class DonutBakingActor extends Actor with ActorLogging {
62 | import context._
63 |
64 | def receive = {
65 | case "BakeDonut" =>
66 | log.info("becoming bake state")
67 | become {
68 | case "BakeVanilla" =>
69 | log.info("baking vanilla")
70 |
71 | case "BakePlain" =>
72 | log.info("baking plain")
73 |
74 | case "StopBaking" =>
75 | log.info("stopping to bake")
76 | unbecome()
77 |
78 | case event @ _ =>
79 | log.info(s"Allowed events [BakeVanilla, BakePlain, StopBaking], event = $event")
80 | }
81 |
82 | case event @ _ =>
83 | log.info(s"Allowed events [BakeDonut], event = $event")
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/test/scala/com/allaboutscala/learn/akka/fsm/DonutBakingActorFSMTests.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.fsm
2 |
3 | import akka.actor.ActorSystem
4 | import akka.testkit.{TestKit, ImplicitSender, DefaultTimeout, TestFSMRef}
5 | import com.allaboutscala.learn.akka.fsm.Tutorial_09_AkkaFSM_PartSix._
6 | import org.scalatest.{WordSpecLike, BeforeAndAfterAll, Matchers}
7 |
8 | /**
9 | * Created by Nadim Bahadoor on 28/06/2016.
10 | *
11 | * Tutorial: Learn How To Use Akka
12 | *
13 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
14 | *
15 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
16 | *
17 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
18 | * use this file except in compliance with the License. You may obtain a copy of
19 | * the License at
20 | *
21 | * [http://www.apache.org/licenses/LICENSE-2.0]
22 | *
23 | * Unless required by applicable law or agreed to in writing, software
24 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
25 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26 | * License for the specific language governing permissions and limitations under
27 | * the License.
28 | */
29 | class DonutBakingActorFSMTests
30 | extends TestKit(ActorSystem("DonutActorFSM"))
31 | with ImplicitSender
32 | with DefaultTimeout
33 | with WordSpecLike
34 | with BeforeAndAfterAll
35 | with Matchers {
36 |
37 | private var donutBakingActorFSM: TestFSMRef[BakingStates, BakingData, DonutBakingActor] = _
38 |
39 | override protected def beforeAll(): Unit = {
40 | donutBakingActorFSM = TestFSMRef(new DonutBakingActor())
41 | }
42 |
43 | "DonutBakingActor" should {
44 | "have initial state of BakingStates.Stop" in {
45 | donutBakingActorFSM.stateName shouldEqual Stop
46 | }
47 | }
48 |
49 | import scala.concurrent.duration._
50 | "DonutBakingActor" should {
51 | "process BakeDonut event and switch to the BakingStates.Start state" in {
52 | donutBakingActorFSM ! BakeDonut
53 | awaitCond(donutBakingActorFSM.stateName == Start, 2 second, 1 second)
54 | }
55 | }
56 |
57 | "DonutBakingActor" should {
58 | "process StopBaking event and switch to BakingStates.Stop state" in {
59 | donutBakingActorFSM ! StopBaking
60 | awaitCond(donutBakingActorFSM.stateName == Stop, 2 second, 1 second)
61 | }
62 | }
63 |
64 |
65 | "DonutBakingActor current donut quantity" should {
66 | "equal to 1 after the StopBaking event" in {
67 | donutBakingActorFSM.stateData.qty shouldEqual 1
68 | }
69 | }
70 |
71 | override protected def afterAll(): Unit = {
72 | TestKit.shutdownActorSystem(system)
73 | }
74 | }
75 |
76 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/actors/Tutorial_04_Ask_Pattern_MapTo.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.actors
2 |
3 | import akka.actor.{Props, Actor, ActorLogging, ActorSystem}
4 | import akka.util.Timeout
5 |
6 | import scala.concurrent.Future
7 |
8 | /**
9 | * Created by Nadim Bahadoor on 28/06/2016.
10 | *
11 | * Tutorial: Learn How To Use Akka
12 | *
13 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
14 | *
15 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
16 | *
17 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
18 | * use this file except in compliance with the License. You may obtain a copy of
19 | * the License at
20 | *
21 | * [http://www.apache.org/licenses/LICENSE-2.0]
22 | *
23 | * Unless required by applicable law or agreed to in writing, software
24 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
25 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26 | * License for the specific language governing permissions and limitations under
27 | * the License.
28 | */
29 | object Tutorial_04_Ask_Pattern_MapTo extends App {
30 |
31 | println("Step 1: Create an actor system")
32 | val system = ActorSystem("DonutStoreActorSystem")
33 |
34 |
35 |
36 | println("\nStep 4: Create DonutInfoActor")
37 | val donutInfoActor = system.actorOf(Props[DonutInfoActor], name = "DonutInfoActor")
38 |
39 |
40 |
41 | println("\nStep 5: Akka Ask Pattern and future mapTo()")
42 | import DonutStoreProtocol._
43 | import akka.pattern._
44 | import scala.concurrent.ExecutionContext.Implicits.global
45 | import scala.concurrent.duration._
46 | implicit val timeout = Timeout(5 second)
47 |
48 | val vanillaDonutFound: Future[Boolean] = (donutInfoActor ? Info("vanilla")).mapTo[Boolean]
49 |
50 | for {
51 | found <- vanillaDonutFound
52 | } yield println(s"Vanilla donut found = $found")
53 |
54 | Thread.sleep(5000)
55 |
56 |
57 |
58 | println("\nStep 2: Define the message passing protocol for our DonutStoreActor")
59 | object DonutStoreProtocol {
60 | case class Info(name: String)
61 | }
62 |
63 |
64 |
65 | println("\nStep 6: close the actor system")
66 | val isTerminated = system.terminate()
67 |
68 |
69 |
70 | println("\nStep 3: Create DonutInfoActor")
71 | class DonutInfoActor extends Actor with ActorLogging {
72 |
73 | import Tutorial_04_Ask_Pattern_MapTo.DonutStoreProtocol._
74 |
75 | def receive = {
76 | case Info(name) if name == "vanilla" =>
77 | log.info(s"Found valid $name donut")
78 | sender ! true
79 |
80 | case Info(name) =>
81 | log.info(s"$name donut is not supported")
82 | sender ! false
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/actors/Tutorial_03_Ask_Pattern.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.actors
2 |
3 | import akka.actor.{Props, Actor, ActorLogging, ActorSystem}
4 | import akka.util.Timeout
5 |
6 | /**
7 | * Created by Nadim Bahadoor on 28/06/2016.
8 | *
9 | * Tutorial: Learn How To Use Akka
10 | *
11 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
12 | *
13 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
14 | *
15 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
16 | * use this file except in compliance with the License. You may obtain a copy of
17 | * the License at
18 | *
19 | * [http://www.apache.org/licenses/LICENSE-2.0]
20 | *
21 | * Unless required by applicable law or agreed to in writing, software
22 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
23 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
24 | * License for the specific language governing permissions and limitations under
25 | * the License.
26 | */
27 | object Tutorial_03_Ask_Pattern extends App {
28 |
29 | println("Step 1: Create an actor system")
30 | val system = ActorSystem("DonutStoreActorSystem")
31 |
32 |
33 |
34 | println("\nStep 4: Create DonutInfoActor")
35 | val donutInfoActor = system.actorOf(Props[DonutInfoActor], name = "DonutInfoActor")
36 |
37 |
38 |
39 | println("\nStep 5: Akka Ask Pattern")
40 | import DonutStoreProtocol._
41 | import akka.pattern._
42 | import scala.concurrent.ExecutionContext.Implicits.global
43 | import scala.concurrent.duration._
44 | implicit val timeout = Timeout(5 second)
45 |
46 | val vanillaDonutFound = donutInfoActor ? Info("vanilla")
47 | for {
48 | found <- vanillaDonutFound
49 | } yield println(s"Vanilla donut found = $found")
50 |
51 | val glazedDonutFound = donutInfoActor ? Info("glazed")
52 | for {
53 | found <- glazedDonutFound
54 | } yield println(s"Glazed donut found = $found")
55 |
56 | Thread.sleep(5000)
57 |
58 |
59 |
60 | println("\nStep 6: Close the actor system")
61 | val isTerminated = system.terminate()
62 |
63 |
64 | println("\nStep 2: Define the message passing protocol for our DonutStoreActor")
65 | object DonutStoreProtocol {
66 | case class Info(name: String)
67 | }
68 |
69 |
70 |
71 | println("\nStep 3: Create DonutInfoActor")
72 | class DonutInfoActor extends Actor with ActorLogging {
73 | import Tutorial_03_Ask_Pattern.DonutStoreProtocol._
74 |
75 | def receive = {
76 | case Info(name) if name == "vanilla" =>
77 | log.info(s"Found valid $name donut")
78 | sender ! true
79 |
80 | case Info(name) =>
81 | log.info(s"$name donut is not supported")
82 | sender ! false
83 | }
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/actors/Tutorial_05_Ask_Pattern_PipeTo.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.actors
2 |
3 | import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
4 | import akka.util.Timeout
5 |
6 | import scala.concurrent.Future
7 |
8 | /**
9 | * Created by Nadim Bahadoor on 28/06/2016.
10 | *
11 | * Tutorial: Learn How To Use Akka
12 | *
13 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
14 | *
15 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
16 | *
17 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
18 | * use this file except in compliance with the License. You may obtain a copy of
19 | * the License at
20 | *
21 | * [http://www.apache.org/licenses/LICENSE-2.0]
22 | *
23 | * Unless required by applicable law or agreed to in writing, software
24 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
25 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26 | * License for the specific language governing permissions and limitations under
27 | * the License.
28 | */
29 | object Tutorial_05_Ask_Pattern_PipeTo extends App {
30 |
31 | println("Step 1: Create an actor system")
32 | val system = ActorSystem("DonutStoreActorSystem")
33 |
34 |
35 |
36 | println("\nStep 4: Create DonutStockActor")
37 | val donutStockActor = system.actorOf(Props[DonutStockActor], name = "DonutStockActor")
38 |
39 |
40 |
41 | println("\nStep 5: Akka Ask Pattern using mapTo() method")
42 | import DonutStoreProtocol._
43 | import akka.pattern._
44 |
45 | import scala.concurrent.ExecutionContext.Implicits.global
46 | import scala.concurrent.duration._
47 | implicit val timeout = Timeout(5 second)
48 |
49 | val vanillaDonutStock: Future[Int] = (donutStockActor ? CheckStock("vanilla")).mapTo[Int]
50 |
51 | for {
52 | found <- vanillaDonutStock
53 | } yield println(s"Vanilla donut stock = $found")
54 |
55 | Thread.sleep(5000)
56 |
57 |
58 |
59 | println("\nStep 6: Close the actor system")
60 | val isTerminated = system.terminate()
61 |
62 |
63 |
64 | println("\nStep 2: Define the message passing protocol for our DonutStoreActor")
65 | object DonutStoreProtocol {
66 | case class Info(name: String)
67 |
68 | case class CheckStock(name: String)
69 | }
70 |
71 |
72 |
73 | println("\nStep 3: Create DonutStockActor")
74 | class DonutStockActor extends Actor with ActorLogging {
75 | import Tutorial_05_Ask_Pattern_PipeTo.DonutStoreProtocol._
76 |
77 | def receive = {
78 | case CheckStock(name) =>
79 | log.info(s"Checking stock for $name donut")
80 | findStock(name).pipeTo(sender)
81 | }
82 |
83 | def findStock(name: String): Future[Int] = Future {
84 | // assume a long running database operation to find stock for the given donut
85 | 100
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/fsm/Tutorial_02_AkkaFSMUnbecome.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.fsm
2 |
3 | import akka.actor.{ActorLogging, Actor, ActorSystem, Props}
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_02_AkkaFSMUnbecome extends App {
27 |
28 | println("Step 1. Create ActorSystem")
29 | val system = ActorSystem("ActorState")
30 |
31 |
32 |
33 | println("\nStep 3: Create DonutBakingActor")
34 | val bakingActor = system.actorOf(Props[DonutBakingActor], "donut-baking-actor")
35 | bakingActor ! "boom" // not valid
36 | Thread.sleep(2000)
37 |
38 |
39 |
40 | println("\nStep 4: Send events to actor to switch states and process events")
41 | bakingActor ! "BakeDonut"
42 | Thread.sleep(2000)
43 |
44 |
45 | bakingActor ! "BakePlain"
46 | Thread.sleep(2000)
47 |
48 |
49 |
50 | bakingActor ! "BakeVanilla"
51 | Thread.sleep(2000)
52 |
53 |
54 |
55 | bakingActor ! "Bake Chocolate"
56 | Thread.sleep(2000)
57 |
58 |
59 |
60 | bakingActor ! "StopBaking"
61 | Thread.sleep(2000)
62 |
63 |
64 |
65 | bakingActor ! "BakeVanilla"
66 | Thread.sleep(2000)
67 |
68 |
69 |
70 | println("\nStep 5: Shutdown actor system")
71 | system.terminate()
72 |
73 |
74 |
75 | println("\nStep 2: Define DonutBakingActor with become() and unbecome() states")
76 | class DonutBakingActor extends Actor with ActorLogging {
77 | import context._
78 |
79 | def receive = {
80 | case "BakeDonut" =>
81 | log.info("becoming bake state")
82 | become {
83 | case "BakeVanilla" =>
84 | log.info("baking vanilla")
85 |
86 | case "BakePlain" =>
87 | log.info("baking plain")
88 |
89 | case "StopBaking" =>
90 | log.info("stopping to bake")
91 | unbecome()
92 |
93 | case event @ _ =>
94 | log.info(s"Allowed events [BakeVanilla, BakePlain, StopBaking], event = $event")
95 | }
96 |
97 | case event @ _ =>
98 | log.info(s"Allowed events [BakeDonut], event = $event")
99 | }
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/fsm/Tutorial_04_AkkaFSM.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.fsm
2 |
3 | import akka.actor.{LoggingFSM, ActorSystem, Props}
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_04_AkkaFSM extends App {
27 |
28 | println("Step 1: Create ActorSystem")
29 | val system = ActorSystem("DonutActorFSM")
30 |
31 |
32 |
33 | println("\nStep 6: Create DonutBakingActor")
34 | val bakingActor = system.actorOf(Props[DonutBakingActor], "donut-baking-actor")
35 |
36 |
37 |
38 | println("\nStep 7: Send events to actor to switch states and process events")
39 | bakingActor ! AddTopping
40 | Thread.sleep(2000)
41 |
42 |
43 |
44 | bakingActor ! BakeDonut
45 | Thread.sleep(2000)
46 |
47 |
48 |
49 | println("\nStep 8: Shutdown actor system")
50 | system.terminate()
51 |
52 |
53 |
54 | println("\nStep 2: Defining events")
55 | sealed trait BakingEvents
56 | case object BakeDonut extends BakingEvents
57 | case object AddTopping extends BakingEvents
58 |
59 |
60 |
61 | println("\nStep 3: Defining states")
62 | sealed trait BakingStates
63 | case object Start extends BakingStates
64 | case object Stop extends BakingStates
65 |
66 |
67 |
68 | println("\nStep 4: Defining mutatable data")
69 | case class BakingData(qty: Int) {
70 | def addOneDonut = copy(qty + 1)
71 | }
72 |
73 | object BakingData {
74 | def initialQuantity = BakingData(0)
75 | }
76 |
77 |
78 | println("\nStep 5: Define DonutBakingActor using LoggingFSM trait")
79 | class DonutBakingActor extends LoggingFSM[BakingStates, BakingData] {
80 | startWith(Stop, BakingData.initialQuantity)
81 |
82 | when(Stop) {
83 | case Event(BakeDonut, _) =>
84 | println("Current state is [Stop], switching to [Start]")
85 | goto(Start).using(stateData.addOneDonut)
86 |
87 | case Event(AddTopping, _) =>
88 | println("Current state is [Stop], you first need to move to [BakeDonut]")
89 | stay
90 | }
91 |
92 | when(Start) {
93 | case _ => throw new IllegalStateException("stop")
94 | }
95 |
96 | initialize()
97 |
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/actors/Tutorial_08_Actor_Lifecycle.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.actors
2 |
3 | import akka.actor.{Props, ActorLogging, Actor, ActorSystem}
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_08_Actor_Lifecycle extends App {
27 |
28 | println("Step 1: Create an actor system")
29 | val system = ActorSystem("DonutStoreActorSystem")
30 |
31 |
32 |
33 | println("\nStep 4: Create DonutInfoActor")
34 | val donutInfoActor = system.actorOf(Props[DonutInfoActor], name = "DonutInfoActor")
35 |
36 |
37 |
38 | println("\nStep 5: Akka Tell Pattern")
39 | import DonutStoreProtocol._
40 | donutInfoActor ! Info("vanilla")
41 |
42 | Thread.sleep(5000)
43 |
44 |
45 |
46 | println("\nStep 6: close the actor system")
47 | val isTerminated = system.terminate()
48 |
49 |
50 |
51 | println("\nStep 2: Define the message passing protocol for our DonutStoreActor")
52 | object DonutStoreProtocol {
53 | case class Info(name: String)
54 | }
55 |
56 |
57 |
58 | println("\nStep 3: Define a BakingActor and a DonutInfoActor")
59 | class BakingActor extends Actor with ActorLogging {
60 |
61 | override def preStart(): Unit = log.info("prestart")
62 |
63 | override def postStop(): Unit = log.info("postStop")
64 |
65 | override def preRestart(reason: Throwable, message: Option[Any]): Unit = log.info("preRestart")
66 |
67 | override def postRestart(reason: Throwable): Unit = log.info("postRestart")
68 |
69 | def receive = {
70 | case Info(name) =>
71 | log.info(s"BakingActor baking $name donut")
72 | }
73 | }
74 |
75 |
76 |
77 | class DonutInfoActor extends Actor with ActorLogging {
78 |
79 | override def preStart(): Unit = log.info("prestart")
80 |
81 | override def postStop(): Unit = log.info("postStop")
82 |
83 | override def preRestart(reason: Throwable, message: Option[Any]): Unit = log.info("preRestart")
84 |
85 | override def postRestart(reason: Throwable): Unit = log.info("postRestart")
86 |
87 | val bakingActor = context.actorOf(Props[BakingActor], name = "BakingActor")
88 |
89 | def receive = {
90 | case msg @ Info(name) =>
91 | log.info(s"Found $name donut")
92 | bakingActor forward msg
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/actors/Tutorial_09_Actor_PoisonPill.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.actors
2 |
3 | import akka.actor._
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_09_Actor_PoisonPill extends App {
27 |
28 | println("Step 1: Create an actor system")
29 | val system = ActorSystem("DonutStoreActorSystem")
30 |
31 |
32 |
33 | println("\nStep 2: Define the message passing protocol for our DonutStoreActor")
34 | object DonutStoreProtocol {
35 | case class Info(name: String)
36 | }
37 |
38 |
39 |
40 | println("\nStep 4: Create DonutInfoActor")
41 | val donutInfoActor = system.actorOf(Props[DonutInfoActor], name = "DonutInfoActor")
42 |
43 |
44 |
45 | println("\nStep 5: Akka Tell Pattern")
46 | import DonutStoreProtocol._
47 | donutInfoActor ! Info("vanilla")
48 |
49 | donutInfoActor ! PoisonPill
50 |
51 | donutInfoActor ! Info("plain")
52 |
53 | Thread.sleep(5000)
54 |
55 |
56 |
57 | println("\nStep 6: close the actor system")
58 | val isTerminated = system.terminate()
59 |
60 |
61 | println("\nStep 3: Define a BakingActor and a DonutInfoActor")
62 | class BakingActor extends Actor with ActorLogging {
63 |
64 | override def preStart(): Unit = log.info("prestart")
65 |
66 | override def postStop(): Unit = log.info("postStop")
67 |
68 | override def preRestart(reason: Throwable, message: Option[Any]): Unit = log.info("preRestart")
69 |
70 | override def postRestart(reason: Throwable): Unit = log.info("postRestart")
71 |
72 | def receive = {
73 | case Info(name) =>
74 | log.info(s"BakingActor baking $name donut")
75 | }
76 | }
77 |
78 |
79 |
80 | class DonutInfoActor extends Actor with ActorLogging {
81 |
82 | override def preStart(): Unit = log.info("prestart")
83 |
84 | override def postStop(): Unit = log.info("postStop")
85 |
86 | override def preRestart(reason: Throwable, message: Option[Any]): Unit = log.info("preRestart")
87 |
88 | override def postRestart(reason: Throwable): Unit = log.info("postRestart")
89 |
90 | val bakingActor = context.actorOf(Props[BakingActor], name = "BakingActor")
91 |
92 | def receive = {
93 | case msg @ Info(name) =>
94 | log.info(s"Found $name donut")
95 | bakingActor forward msg
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/dispatchers/Tutorial_05_PinnedDispatcher.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.dispatchers
2 |
3 | import java.util.concurrent.TimeUnit
4 |
5 | import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
6 | import akka.util.Timeout
7 |
8 | import scala.concurrent.duration._
9 | import scala.concurrent.{Await, Future}
10 |
11 | /**
12 | * Created by Nadim Bahadoor on 28/06/2016.
13 | *
14 | * Tutorial: Learn How To Use Akka
15 | *
16 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
17 | *
18 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
19 | *
20 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
21 | * use this file except in compliance with the License. You may obtain a copy of
22 | * the License at
23 | *
24 | * [http://www.apache.org/licenses/LICENSE-2.0]
25 | *
26 | * Unless required by applicable law or agreed to in writing, software
27 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
28 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
29 | * License for the specific language governing permissions and limitations under
30 | * the License.
31 | */
32 | object Tutorial_05_PinnedDispatcher extends App {
33 | println("Step 1: Create actor system")
34 | val system = ActorSystem("DonutStoreActorSystem")
35 |
36 |
37 |
38 | println("\nStep 2: Create pinned thread pool configuration in application.conf")
39 |
40 |
41 |
42 | println("Step 3: Lookup our pinned-thread-pool dispatcher from application.conf")
43 | import DonutStoreProtocol._
44 | import akka.pattern._
45 | implicit val timeout = Timeout(1, TimeUnit.MINUTES)
46 | implicit val executionContext = system.dispatchers.lookup("pinned-thread-pool")
47 |
48 |
49 |
50 | println("\nStep 6: Create 2 requests")
51 | val clientRequests = (1 to 2).map(i => StockRequest(s"vanilla donut", i))
52 | val futures = clientRequests.map{ stock =>
53 | val actorRef = system
54 | .actorOf(Props[DonutStockRequestActor]
55 | .withDispatcher("pinned-thread-pool"))
56 | (actorRef ? stock).mapTo[DonutStockRequest]
57 | // (actorRef ? stock).mapTo[DonutStockRequest]
58 | }
59 | val results = Await.result(Future.sequence(futures), 1 minute)
60 | results.foreach(println(_))
61 |
62 |
63 |
64 | println("\nStep 7: Close actor system")
65 | system.terminate()
66 |
67 |
68 |
69 | println("\nStep 4: Create protocol")
70 | object DonutStoreProtocol {
71 | case class StockRequest(name: String, clientId: Int)
72 |
73 | trait Result
74 | case class DonutStockRequest(quantity: Int) extends Result
75 | case class DonutFailure(msg: String) extends Result
76 | }
77 |
78 |
79 |
80 | println("\nStep 5: Create DonutStockRequestActor")
81 | class DonutStockRequestActor extends Actor with ActorLogging {
82 | val randomStock = scala.util.Random
83 | def receive = {
84 | case StockRequest(name, clientId) =>
85 | log.info(s"CHECKING: donut stock for name = $name, clientId = $clientId")
86 | Thread.sleep(5000)
87 | log.info(s"FINISHED: donut stock for name = $name, clientId = $clientId")
88 | sender() ! DonutStockRequest(randomStock.nextInt(100))
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/dispatchers/Tutorial_04_AkkaResizableThreadPool.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.dispatchers
2 |
3 | import java.util.concurrent.TimeUnit
4 |
5 | import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
6 | import akka.util.Timeout
7 |
8 | import scala.concurrent.duration.Duration
9 | import scala.concurrent.{Await, Future}
10 |
11 | /**
12 | * Created by Nadim Bahadoor on 28/06/2016.
13 | *
14 | * Tutorial: Learn How To Use Akka
15 | *
16 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
17 | *
18 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
19 | *
20 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
21 | * use this file except in compliance with the License. You may obtain a copy of
22 | * the License at
23 | *
24 | * [http://www.apache.org/licenses/LICENSE-2.0]
25 | *
26 | * Unless required by applicable law or agreed to in writing, software
27 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
28 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
29 | * License for the specific language governing permissions and limitations under
30 | * the License.
31 | */
32 | object Tutorial_04_AkkaResizableThreadPool extends App {
33 | println("Step 1: Create actor system")
34 | val system = ActorSystem("DonutStoreActorSystem")
35 |
36 |
37 |
38 | println("\nStep 2: Create resizable thread pool configuration in application.conf")
39 |
40 |
41 |
42 |
43 | println("Step 3: Lookup our resizable-thread-pool dispatcher from application.conf")
44 | import DonutStoreProtocol._
45 | import akka.pattern._
46 | implicit val timeout = Timeout(1, TimeUnit.MINUTES)
47 | implicit val executionContext = system.dispatchers.lookup("resizable-thread-pool")
48 |
49 |
50 |
51 | println("\nStep 6: Create 10 requests using pool-size = 10")
52 | val clientRequests = (1 to 10).map(i => StockRequest(s"vanilla donut", i))
53 | val futures = clientRequests.map{ stock =>
54 | val actorRef = system
55 | .actorOf(Props[DonutStockRequestActor]
56 | .withDispatcher("resizable-thread-pool"))
57 | (actorRef ? stock).mapTo[DonutStockRequest]
58 | }
59 |
60 | val results = Await.result(Future.sequence(futures), Duration.Inf)
61 | results.foreach(println(_))
62 |
63 |
64 |
65 | println("\nStep 8: Close actor system")
66 | system.terminate()
67 |
68 |
69 |
70 | println("\nStep 4: Create protocol")
71 | object DonutStoreProtocol {
72 | case class StockRequest(name: String, clientId: Int)
73 |
74 | trait Result
75 | case class DonutStockRequest(quantity: Int) extends Result
76 | case class DonutFailure(msg: String) extends Result
77 | }
78 |
79 |
80 |
81 | println("\nStep 5: Create DonutStockRequestActor")
82 | class DonutStockRequestActor extends Actor with ActorLogging {
83 | val randomStock = scala.util.Random
84 | def receive = {
85 | case StockRequest(name, clientId) =>
86 | log.info(s"CHECKING: donut stock for name = $name, clientId = $clientId")
87 | Thread.sleep(5000)
88 | log.info(s"FINISHED: donut stock for name = $name, clientId = $clientId")
89 | sender() ! DonutStockRequest(randomStock.nextInt(100))
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/dispatchers/Tutorial_03_AkkaFixedThreadPoolDispatcher.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.dispatchers
2 |
3 | import java.util.concurrent.TimeUnit
4 |
5 | import akka.actor.{ActorLogging, Actor, Props, ActorSystem}
6 | import akka.util.Timeout
7 | import scala.concurrent.duration._
8 |
9 | import scala.concurrent.{Future, Await}
10 |
11 | /**
12 | * Created by Nadim Bahadoor on 28/06/2016.
13 | *
14 | * Tutorial: Learn How To Use Akka
15 | *
16 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
17 | *
18 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
19 | *
20 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
21 | * use this file except in compliance with the License. You may obtain a copy of
22 | * the License at
23 | *
24 | * [http://www.apache.org/licenses/LICENSE-2.0]
25 | *
26 | * Unless required by applicable law or agreed to in writing, software
27 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
28 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
29 | * License for the specific language governing permissions and limitations under
30 | * the License.
31 | */
32 | object Tutorial_03_AkkaFixedThreadPoolDispatcher extends App {
33 | println("Step 1: Create actor system")
34 | val system = ActorSystem("DonutStoreActorSystem")
35 |
36 |
37 |
38 | println("\nStep 2: Create fixed thread pool configuration in application.conf")
39 |
40 |
41 |
42 | println("Step 3: Lookup our fixed-thread-pool dispatcher from application.conf")
43 | import DonutStoreProtocol._
44 | import akka.pattern._
45 | implicit val timeout = Timeout(1, TimeUnit.MINUTES)
46 | implicit val executionContext = system.dispatchers.lookup("fixed-thread-pool")
47 |
48 |
49 | println("\nStep 6: Create 10 requests using pool-size = 10")
50 | println("\nStep 7: Create 10 requests using pool-size = 5")
51 | val clientRequests = (1 to 10).map(i => StockRequest(s"vanilla donut", i))
52 | val futures = clientRequests.map{ stock =>
53 | val actorRef = system
54 | .actorOf(Props[DonutStockRequestActor]
55 | .withDispatcher("fixed-thread-pool"))
56 | (actorRef ? stock).mapTo[DonutStockRequest]
57 | }
58 | val results = Await.result(Future.sequence(futures), 1 minute)
59 | results.foreach(println(_))
60 |
61 |
62 |
63 | println("\nStep 8: Close actor system")
64 | system.terminate()
65 |
66 |
67 |
68 | println("\nStep 4: Create protocol")
69 | object DonutStoreProtocol {
70 | case class StockRequest(name: String, clientId: Int)
71 |
72 | trait Result
73 | case class DonutStockRequest(quantity: Int) extends Result
74 | case class DonutFailure(msg: String) extends Result
75 | }
76 |
77 |
78 |
79 | println("\nStep 5: Create DonutStockRequestActor")
80 | class DonutStockRequestActor extends Actor with ActorLogging {
81 | val randomStock = scala.util.Random
82 | def receive = {
83 | case StockRequest(name, clientId) =>
84 | log.info(s"CHECKING: donut stock for name = $name, clientId = $clientId")
85 | Thread.sleep(5000)
86 | log.info(s"FINISHED: donut stock for name = $name, clientId = $clientId")
87 | sender() ! DonutStockRequest(randomStock.nextInt(100))
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/client/AkkaHTTPClient.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.client
2 |
3 | import akka.actor.ActorSystem
4 | import akka.http.scaladsl.Http
5 | import akka.http.scaladsl.model.{MediaTypes, HttpEntity, HttpMethods, HttpRequest}
6 | import akka.http.scaladsl.unmarshalling.Unmarshal
7 | import akka.stream.ActorMaterializer
8 | import akka.util.ByteString
9 | import com.allaboutscala.learn.akka.http.jsonsupport.{Donuts, JsonSupport}
10 |
11 | import scala.concurrent.{Await, Future}
12 | import scala.util.{Failure, Success}
13 | import scala.concurrent.duration._
14 |
15 | /**
16 | * Created by Nadim Bahadoor on 28/06/2016.
17 | *
18 | * Tutorial: Learn How To Use Akka HTTP
19 | *
20 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
21 | *
22 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
23 | *
24 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
25 | * use this file except in compliance with the License. You may obtain a copy of
26 | * the License at
27 | *
28 | * [http://www.apache.org/licenses/LICENSE-2.0]
29 | *
30 | * Unless required by applicable law or agreed to in writing, software
31 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
32 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
33 | * License for the specific language governing permissions and limitations under
34 | * the License.
35 | */
36 | object AkkaHttpClient extends App with JsonSupport {
37 |
38 | implicit val system = ActorSystem("akka-http-donuts-client")
39 | implicit val materializer = ActorMaterializer()
40 | implicit val ec = system.dispatcher
41 |
42 | // HTTP GET request
43 | val donutsUri = "http://localhost:8080/donuts"
44 | val donutsHttpRequest = HttpRequest(
45 | uri = donutsUri,
46 | method = HttpMethods.GET
47 | )
48 |
49 | val donutsResponse = Http().singleRequest(donutsHttpRequest)
50 | donutsResponse
51 | .onComplete {
52 | case Success(donutsResponse) =>
53 | println(s"Raw HttpResponse = $donutsResponse")
54 |
55 | // You obviously should not block using Await.result(...) and use flatMap or other similar future sequencing mechanics
56 | val donutsF: Future[Donuts] = Unmarshal(donutsResponse).to[Donuts]
57 | val donuts: Donuts = Await.result(donutsF, 5.second)
58 | println(s"Unmarshalled HttpResponse to Case Class = $donuts")
59 |
60 |
61 | case Failure(e) => println(s"Failed to HTTP GET $donutsUri, error = ${e.getMessage}")
62 | }
63 |
64 | Thread.sleep(3000)
65 |
66 |
67 |
68 | // HTTP POST request
69 | val jsonDonutInput = ByteString("""{"name":"plain donut", "price":1.50}""")
70 | val httpPostCreateDonut = HttpRequest(
71 | uri = "http://localhost:8080/create-donut",
72 | method = HttpMethods.POST,
73 | entity = HttpEntity(MediaTypes.`application/json`, jsonDonutInput))
74 |
75 | val createDonutF = for {
76 | response <- Http().singleRequest(httpPostCreateDonut)
77 | _ = println(s"Akka HTTP request status = ${response.status}")
78 | if response.status.isSuccess()
79 | output <- Unmarshal(response).to[String]
80 | } yield println(s"HTTP POST request output = $output")
81 |
82 | Await.result(createDonutF, 5.second)
83 |
84 |
85 | system.terminate()
86 | }
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/fsm/Tutorial_03_AkkaFSMProtocol.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.fsm
2 |
3 | import akka.actor.{Props, ActorSystem, Actor}
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_03_AkkaFSMProtocol extends App {
27 |
28 | println("Step 1. Create ActorSystem")
29 | val system = ActorSystem("ActorState")
30 |
31 |
32 |
33 | println("\nStep 4: Create DonutBakingActor")
34 | val bakingActor = system.actorOf(Props[DonutBakingActor], "donut-baking-actor")
35 | bakingActor ! "boom" // not valid
36 | Thread.sleep(2000)
37 |
38 |
39 |
40 | println("\nStep 5: Send events to actor to switch states and process events")
41 | bakingActor ! BakeDonut
42 | Thread.sleep(2000)
43 |
44 |
45 |
46 | bakingActor ! BakePlain
47 | Thread.sleep(2000)
48 |
49 |
50 |
51 | bakingActor ! BakeVanilla
52 | Thread.sleep(2000)
53 |
54 |
55 |
56 | bakingActor ! "Bake Chocolate"
57 | Thread.sleep(2000)
58 |
59 |
60 |
61 | bakingActor ! StopBaking
62 | Thread.sleep(2000)
63 |
64 |
65 |
66 | bakingActor ! BakeVanilla
67 | Thread.sleep(2000)
68 |
69 |
70 |
71 | println("\nStep 6: Shutdown actor system")
72 | system.terminate()
73 |
74 |
75 |
76 | println("\nStep 2: Define message passing protocol using sealed trait")
77 | sealed trait DonutProtocol
78 | case object BakeDonut extends DonutProtocol
79 | case object BakeVanilla extends DonutProtocol
80 | case object BakePlain extends DonutProtocol
81 | case object StopBaking extends DonutProtocol
82 |
83 |
84 |
85 | println("\nStep 2: Define DonutBakingActor with become() and unbecome() event")
86 | class DonutBakingActor extends Actor {
87 | import context._
88 |
89 | def startBaking: Receive = {
90 | case BakeDonut =>
91 | println("becoming bake state")
92 | become(bake)
93 |
94 | case event @ _ =>
95 | println(s"Allowed event [$BakeDonut], event = $event")
96 | }
97 |
98 | def bake: Receive = {
99 | case BakeVanilla =>
100 | println("baking vanilla")
101 |
102 | case BakePlain =>
103 | println("baking plain")
104 |
105 | case StopBaking =>
106 | println("stopping to bake")
107 | unbecome()
108 |
109 | case event @ _ =>
110 | println(s"Allowed event [$BakeVanilla, $BakePlain, $StopBaking], event = $event")
111 | }
112 |
113 | def receive = startBaking
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/fsm/Tutorial_05_AkkaFSM_PartTwo.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.fsm
2 |
3 | import akka.actor.{LoggingFSM, Props, ActorSystem}
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_05_AkkaFSM_PartTwo extends App {
27 |
28 | println("Step 1: Create ActorSystem")
29 | val system = ActorSystem("DonutActorFSM")
30 |
31 |
32 | println("\nStep 6: Create DonutBakingActor")
33 | val bakingActor = system.actorOf(Props[DonutBakingActor], "donut-baking-actor")
34 |
35 |
36 |
37 | println("\nStep 7: Send events to actor to switch states and process events")
38 | bakingActor ! AddTopping
39 | Thread.sleep(2000)
40 |
41 |
42 |
43 | bakingActor ! BakeDonut
44 | Thread.sleep(2000)
45 |
46 |
47 |
48 | bakingActor ! StopBaking
49 | Thread.sleep(2000)
50 |
51 |
52 |
53 | bakingActor ! AddTopping
54 | Thread.sleep(2000)
55 |
56 |
57 | println("\nStep 8: Shutdown actor system")
58 | system.terminate()
59 |
60 |
61 |
62 | println("\nStep 2: Defining events")
63 | sealed trait BakingEvents
64 | case object BakeDonut extends BakingEvents
65 | case object AddTopping extends BakingEvents
66 | case object StopBaking extends BakingEvents
67 |
68 |
69 |
70 | println("\nStep 3: Defining states")
71 | sealed trait BakingStates
72 | case object Start extends BakingStates
73 | case object Stop extends BakingStates
74 |
75 |
76 |
77 | println("\nStep 4: Defining mutatable data")
78 | case class BakingData(qty: Int) {
79 | def addOneDonut = copy(qty + 1)
80 | }
81 |
82 | object BakingData {
83 | def initialQuantity = BakingData(0)
84 | }
85 |
86 |
87 |
88 | println("\nStep 5: Define DonutBakingActor using LoggingFSM trait")
89 | class DonutBakingActor extends LoggingFSM[BakingStates, BakingData] {
90 | startWith(Stop, BakingData.initialQuantity)
91 |
92 | when(Stop) {
93 | case Event(BakeDonut, _) =>
94 | println("Current state is [Stop], switching to [Start]")
95 | goto(Start).using(stateData.addOneDonut)
96 |
97 | case Event(AddTopping, _) =>
98 | println("Current state is [Stop], you first need to move to [BakeDonut]")
99 | stay
100 | }
101 |
102 | when(Start) {
103 | case Event(StopBaking, _) =>
104 | println(s"Event StopBaking, current donut quantity = ${stateData.qty}")
105 | goto(Stop)
106 | }
107 |
108 | initialize()
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/fsm/Tutorial_06_AkkaFSM_PartThree.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.fsm
2 |
3 | import akka.actor.{ActorSystem, Props, LoggingFSM}
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_06_AkkaFSM_PartThree extends App {
27 |
28 | println("Step 1: Create ActorSystem")
29 | val system = ActorSystem("DonutActorFSM")
30 |
31 |
32 |
33 | println("\nStep 6: Create DonutBakingActor")
34 | val bakingActor = system.actorOf(Props[DonutBakingActor], "donut-baking-actor")
35 |
36 |
37 |
38 | println("\nStep 7: Send events to actor to switch states and process events")
39 | bakingActor ! BakeDonut
40 | Thread.sleep(2000)
41 |
42 |
43 |
44 | bakingActor ! "some random event"
45 | Thread.sleep(2000)
46 |
47 |
48 |
49 | println("\nStep 8: Shutdown actor system")
50 | system.terminate()
51 |
52 |
53 |
54 | println("\nStep 2: Defining events")
55 | sealed trait BakingEvents
56 | case object BakeDonut extends BakingEvents
57 | case object AddTopping extends BakingEvents
58 | case object StopBaking extends BakingEvents
59 |
60 |
61 |
62 | println("\nStep 3: Defining states")
63 | sealed trait BakingStates
64 | case object Start extends BakingStates
65 | case object Stop extends BakingStates
66 |
67 |
68 |
69 | println("\nStep 4: Defining mutatable data")
70 | case class BakingData(qty: Int) {
71 | def addOneDonut = copy(qty + 1)
72 | }
73 |
74 | object BakingData {
75 | def initialQuantity = BakingData(0)
76 | }
77 |
78 |
79 |
80 | println("\nStep 5: Define DonutBakingActor using LoggingFSM trait")
81 | class DonutBakingActor extends LoggingFSM[BakingStates, BakingData] {
82 | startWith(Stop, BakingData.initialQuantity)
83 |
84 | when(Stop) {
85 | case Event(BakeDonut, _) =>
86 | println("Current state is [Stop], switching to [Start]")
87 | goto(Start).using(stateData.addOneDonut)
88 |
89 | case Event(AddTopping, _) =>
90 | println("Current state is [Stop], you first need to move to [BakeDonut]")
91 | stay
92 | }
93 |
94 |
95 | when(Start) {
96 | case Event(StopBaking, _) =>
97 | println(s"Event StopBaking, current donut quantity = ${stateData.qty}")
98 | goto(Stop)
99 | }
100 |
101 |
102 | whenUnhandled {
103 | case Event(event, stateData) =>
104 | println(s"We've received an unhandled event = [$event] for the state data = [$stateData]")
105 | goto(Stop)
106 | }
107 |
108 | initialize()
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/http/AkkaHttpServer.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.http
2 |
3 | import akka.actor.ActorSystem
4 | import akka.http.scaladsl.Http
5 | import akka.http.scaladsl.model.StatusCodes
6 | import akka.http.scaladsl.server.Directives._
7 | import akka.http.scaladsl.server._
8 | import akka.stream.ActorMaterializer
9 | import com.allaboutscala.learn.akka.http.routes.{DonutRoutes, ServerVersion}
10 | import com.typesafe.scalalogging.LazyLogging
11 |
12 | import scala.io.StdIn
13 | import scala.util.{Failure, Success}
14 |
15 | /**
16 | * Created by Nadim Bahadoor on 28/06/2016.
17 | *
18 | * Tutorial: Learn How To Use Akka HTTP
19 | *
20 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
21 | *
22 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
23 | *
24 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
25 | * use this file except in compliance with the License. You may obtain a copy of
26 | * the License at
27 | *
28 | * [http://www.apache.org/licenses/LICENSE-2.0]
29 | *
30 | * Unless required by applicable law or agreed to in writing, software
31 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
32 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
33 | * License for the specific language governing permissions and limitations under
34 | * the License.
35 | */
36 | object AkkaHttpServer extends App with LazyLogging {
37 |
38 | implicit val system = ActorSystem("akka-http-rest-server")
39 | implicit val materializer = ActorMaterializer()
40 | implicit val ec = system.dispatcher
41 |
42 | // these should ideally be in some configuration file
43 | val host = "127.0.0.1"
44 | val port = 8080
45 |
46 | implicit val globalRejectionHandler =
47 | RejectionHandler.newBuilder()
48 | .handle { case ValidationRejection(msg, route) =>
49 | complete(StatusCodes.InternalServerError, s"The operation is not supported, error = $msg")
50 | }
51 | .handleNotFound {
52 | complete(StatusCodes.NotFound, "The path is not supported.")
53 | }
54 | .result()
55 |
56 |
57 | implicit val globalExceptionHandler = ExceptionHandler {
58 | case e: RuntimeException => complete(s"A runtime exception occurred with, msg = ${e.getMessage}")
59 | }
60 |
61 |
62 | // // routes
63 | // val serverUpRoute: Route = get {
64 | // complete("Akka HTTP Server is UP.")
65 | // }
66 |
67 | val serverVersion = new ServerVersion()
68 | val serverVersionRoute = serverVersion.route()
69 | val serverVersionRouteAsJson = serverVersion.routeAsJson()
70 | val serverVersionJsonEncoding = serverVersion.routeAsJsonEncoding()
71 | val donutRoutes = new DonutRoutes().route()
72 |
73 | val routes: Route = donutRoutes ~ serverVersionRoute ~ serverVersionRouteAsJson ~ serverVersionJsonEncoding//
74 | // ~ serverUpRoute
75 |
76 | val httpServerFuture = Http().bindAndHandle(routes, host, port)
77 | httpServerFuture.onComplete {
78 | case Success(binding) =>
79 | logger.info(s"Akka Http Server is UP and is bound to ${binding.localAddress}")
80 |
81 | case Failure(e) =>
82 | logger.error(s"Akka Http server failed to start", e)
83 | system.terminate()
84 | }
85 |
86 | StdIn.readLine() // let it run until user presses return
87 | httpServerFuture
88 | .flatMap(_.unbind()) // trigger unbinding from the port
89 | .onComplete(_ => system.terminate()) // and shutdown when done
90 | }
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/fsm/Tutorial_07_AkkaFSM_PartFour.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.fsm
2 |
3 | import akka.actor.{LoggingFSM, Props, ActorSystem}
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_07_AkkaFSM_PartFour extends App {
27 |
28 | println("Step 1: Create ActorSystem")
29 | val system = ActorSystem("DonutActorFSM")
30 |
31 |
32 |
33 | println("\nStep 6: Create DonutBakingActor")
34 | val bakingActor = system.actorOf(Props[DonutBakingActor], "donut-baking-actor")
35 |
36 |
37 |
38 | println("\nStep 7: Send events to actor to switch states and process events")
39 | bakingActor ! BakeDonut
40 | Thread.sleep(2000)
41 |
42 |
43 |
44 | bakingActor ! StopBaking
45 | Thread.sleep(2000)
46 |
47 |
48 |
49 | println("\nStep 8: Shutdown actor system")
50 | system.terminate()
51 |
52 |
53 |
54 | println("\nStep 2: Defining events")
55 | sealed trait BakingEvents
56 | case object BakeDonut extends BakingEvents
57 | case object AddTopping extends BakingEvents
58 | case object StopBaking extends BakingEvents
59 |
60 |
61 |
62 | println("\nStep 3: Defining states")
63 | sealed trait BakingStates
64 | case object Start extends BakingStates
65 | case object Stop extends BakingStates
66 |
67 |
68 |
69 | println("\nStep 4: Defining mutatable data")
70 | case class BakingData(qty: Int) {
71 | def addOneDonut = copy(qty + 1)
72 | }
73 |
74 | object BakingData {
75 | def initialQuantity = BakingData(0)
76 | }
77 |
78 |
79 |
80 | println("\nStep 5: Define DonutBakingActor using LoggingFSM trait")
81 | class DonutBakingActor extends LoggingFSM[BakingStates, BakingData] {
82 | startWith(Stop, BakingData.initialQuantity)
83 |
84 | when(Stop) {
85 | case Event(BakeDonut, _) =>
86 | println("Current state is [Stop], switching to [Start]")
87 | goto(Start).using(stateData.addOneDonut)
88 |
89 | case Event(AddTopping, _) =>
90 | println("Current state is [Stop], you first need to move to [BakeDonut]")
91 | stay
92 | }
93 |
94 | when(Start) {
95 | case Event(StopBaking, _) =>
96 | println(s"Event StopBaking, current donut quantity = ${stateData.qty}")
97 | goto(Stop)
98 | }
99 |
100 | whenUnhandled {
101 | case Event(event, stateData) =>
102 | println(s"We've received an unhandled event = [$event] for the state data = [$stateData]")
103 | goto(Stop)
104 | }
105 |
106 | onTransition {
107 | case Stop -> Start => println("Switching state from [Stop -> Start]")
108 | case Start -> Stop => println("Switching state from [Start -> Stop]")
109 | }
110 |
111 | initialize()
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/fsm/Tutorial_08_AkkaFSM_PartFive.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.fsm
2 |
3 | import akka.actor.{LoggingFSM, Props, ActorSystem}
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_08_AkkaFSM_PartFive extends App {
27 |
28 | println("Step 1: Create ActorSystem")
29 | val system = ActorSystem("DonutActorFSM")
30 |
31 |
32 |
33 | println("\nStep 6: Create DonutBakingActor")
34 | val bakingActor = system.actorOf(Props[DonutBakingActor], "donut-baking-actor")
35 |
36 |
37 |
38 | println("\nStep 7: Send events to actor to switch states and process events")
39 | bakingActor ! BakeDonut
40 | Thread.sleep(10000)
41 |
42 |
43 |
44 | bakingActor ! AddTopping
45 | Thread.sleep(2000)
46 |
47 |
48 |
49 | println("\nStep 8: Shutdown actor system")
50 | system.terminate()
51 |
52 |
53 |
54 | println("\nStep 2: Defining events")
55 | sealed trait BakingEvents
56 | case object BakeDonut extends BakingEvents
57 | case object AddTopping extends BakingEvents
58 | case object StopBaking extends BakingEvents
59 |
60 |
61 |
62 | println("\nStep 3: Defining states")
63 | sealed trait BakingStates
64 | case object Start extends BakingStates
65 | case object Stop extends BakingStates
66 |
67 |
68 |
69 | println("\nStep 4: Defining mutatable data")
70 | case class BakingData(qty: Int) {
71 | def addOneDonut = copy(qty + 1)
72 | }
73 |
74 | object BakingData {
75 | def initialQuantity = BakingData(0)
76 | }
77 |
78 |
79 |
80 | println("\nStep 5: Define DonutBakingActor using LoggingFSM trait")
81 | class DonutBakingActor extends LoggingFSM[BakingStates, BakingData] {
82 | startWith(Stop, BakingData.initialQuantity)
83 |
84 | when(Stop) {
85 | case Event(BakeDonut, _) =>
86 | println("Current state is [Stop], switching to [Start]")
87 | goto(Start).using(stateData.addOneDonut)
88 |
89 | case Event(AddTopping, _) =>
90 | println("Current state is [Stop], you first need to move to [BakeDonut]")
91 | stay
92 | }
93 |
94 | import scala.concurrent.duration._
95 | when(Start, stateTimeout = 5 second) {
96 | case Event(StopBaking, _) =>
97 | println(s"Event StopBaking, current donut quantity = ${stateData.qty}")
98 | goto(Stop)
99 |
100 | case Event(StateTimeout, _) =>
101 | println("Timing out state = [Start], switching to state = [Stop]")
102 | goto(Stop)
103 | }
104 |
105 | whenUnhandled {
106 | case Event(event, stateData) =>
107 | println(s"We've received an unhandled event = [$event] for the state data = [$stateData]")
108 | goto(Stop)
109 | }
110 |
111 | onTransition {
112 | case Stop -> Start => println("Switching state from [Stop -> Start]")
113 | case Start -> Stop => println("Switching state from [Start -> Stop]")
114 | }
115 |
116 | initialize()
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/test/scala/com/allaboutscala/learn/akka/fsm/DonutInfoActorTests.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.fsm
2 |
3 | import akka.actor.{Actor, ActorLogging, ActorSystem}
4 | import akka.testkit.{TestActorRef, DefaultTimeout, ImplicitSender, TestKit}
5 | import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}
6 |
7 | import scala.util.Success
8 |
9 | /**
10 | * Created by Nadim Bahadoor on 28/06/2016.
11 | *
12 | * Tutorial: Learn How To Use Akka
13 | *
14 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
15 | *
16 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
17 | *
18 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
19 | * use this file except in compliance with the License. You may obtain a copy of
20 | * the License at
21 | *
22 | * [http://www.apache.org/licenses/LICENSE-2.0]
23 | *
24 | * Unless required by applicable law or agreed to in writing, software
25 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
26 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
27 | * License for the specific language governing permissions and limitations under
28 | * the License.
29 | */
30 | class DonutInfoActorTests
31 | extends TestKit(ActorSystem("DonutActorTests"))
32 | with ImplicitSender
33 | with DefaultTimeout
34 | with WordSpecLike
35 | with BeforeAndAfterAll
36 | with Matchers {
37 |
38 | import DonutStoreProtocol._
39 | "Sending Tell Pattern Info(vanilla) message to DonutInfoActor" should {
40 | "reply back with true" in {
41 | val testActor = TestActorRef[DonutInfoActor]
42 | testActor ! Info("vanilla")
43 | expectMsg(true)
44 | }
45 | }
46 |
47 |
48 |
49 | import scala.concurrent.duration._
50 | "DonutInfoActor" should {
51 | "respond back within 100 millis" in {
52 | within(100 millis) {
53 | val testActor = TestActorRef[DonutInfoActor]
54 | testActor ! Info("vanilla")
55 | Thread.sleep(500)
56 | expectMsg(true)
57 | }
58 | }
59 | }
60 |
61 |
62 |
63 | "Sending Ask Pattern Info(plain) message to DonutInfoActor" should {
64 | "reply back with false" in {
65 | import akka.pattern._
66 | val testActor = TestActorRef[DonutInfoActor]
67 | val result = testActor ? Info("plain")
68 | val Success(reply: Boolean) = result.value.get
69 | reply shouldBe false
70 | }
71 | }
72 |
73 |
74 |
75 | "Sending a Random Donut message to DonutInfoActor" should {
76 | "throw IllegalStateException" in {
77 | val testActor = TestActorRef[DonutInfoActor]
78 | intercept[IllegalStateException] {
79 | testActor.receive("Random Donut")
80 | }
81 | }
82 | }
83 |
84 |
85 |
86 | "The exception message when sending a Random Donut to DonutInfoActor" should {
87 | "include the words: is not allowed" in {
88 | val testActor = TestActorRef[DonutInfoActor]
89 | val exception = the [IllegalStateException] thrownBy {
90 | testActor.receive("Random Donut")
91 | }
92 | exception.getClass shouldEqual classOf[java.lang.IllegalStateException]
93 | exception.getMessage should be ("Event Random Donut is not allowed")
94 | }
95 | }
96 |
97 |
98 |
99 | override protected def afterAll(): Unit = {
100 | TestKit.shutdownActorSystem(system)
101 | }
102 | }
103 |
104 | object DonutStoreProtocol {
105 | case class Info(name: String)
106 | }
107 |
108 | class DonutInfoActor extends Actor with ActorLogging {
109 | import DonutStoreProtocol._
110 |
111 | def receive = {
112 | case Info(name) if name == "vanilla" =>
113 | log.info(s"Found valid $name donut")
114 | sender ! true
115 |
116 | case Info(name) =>
117 | log.info(s"$name donut is not supported")
118 | sender ! false
119 |
120 | case event @ _ =>
121 | log.info(s"Event $event is not allowed.")
122 | throw new IllegalStateException(s"Event $event is not allowed")
123 | }
124 | }
--------------------------------------------------------------------------------
/source-code/learn-akka/src/test/scala/com/allaboutscala/learn/akka/http/DonutQueryParametersTest.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.http
2 |
3 | import akka.http.scaladsl.model.StatusCodes
4 | import akka.http.scaladsl.server.Route
5 | import akka.http.scaladsl.testkit.ScalatestRouteTest
6 | import com.allaboutscala.learn.akka.http.routes.DonutRoutes
7 | import org.scalatest.{Matchers, WordSpec}
8 |
9 | /**
10 | * Created by Nadim Bahadoor on 28/06/2016.
11 | *
12 | * Tutorial: Learn How To Use Akka HTTP
13 | *
14 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
15 | *
16 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
17 | *
18 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
19 | * use this file except in compliance with the License. You may obtain a copy of
20 | * the License at
21 | *
22 | * [http://www.apache.org/licenses/LICENSE-2.0]
23 | *
24 | * Unless required by applicable law or agreed to in writing, software
25 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
26 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
27 | * License for the specific language governing permissions and limitations under
28 | * the License.
29 | */
30 | class DonutQueryParametersTest
31 | extends WordSpec
32 | with Matchers
33 | with ScalatestRouteTest {
34 |
35 | val donutRoutes = new DonutRoutes().route()
36 |
37 | "Query Parameters Tests" should {
38 | "match the output for the URL /donut/prices?donutName" in {
39 | Get("/donut/prices?donutName=plain%20donut") ~> donutRoutes ~> check {
40 | responseAs[String] shouldEqual "Received parameter: donutName=plain donut"
41 | status shouldEqual StatusCodes.OK
42 | }
43 | }
44 |
45 |
46 |
47 | "Check for required donutName query parameter at /donut/prices" in {
48 | Get("/donut/prices?") ~> Route.seal(donutRoutes) ~> check {
49 | responseAs[String] shouldEqual "Request is missing required query parameter 'donutName'"
50 | status shouldEqual StatusCodes.NotFound
51 | }
52 | }
53 |
54 |
55 |
56 | "Validate the pass-through of required and optional parameters in /donut/bake" in {
57 | Get("/donut/bake?donutName=plain%20donut&topping=chocolate") ~> donutRoutes ~> check {
58 | responseAs[String] shouldEqual "Received parameters: donutName=plain donut and topping=chocolate"
59 | status shouldEqual StatusCodes.OK
60 | }
61 | }
62 |
63 |
64 |
65 | "Verify the optional parameter topping for /donut/bake" in {
66 | Get("/donut/bake?donutName=plain%20donut") ~> donutRoutes ~> check {
67 | responseAs[String] shouldEqual "Received parameters: donutName=plain donut and topping=sprinkles"
68 | status shouldEqual StatusCodes.OK
69 | }
70 | }
71 |
72 |
73 |
74 | "Verify typed parameters for /ingredients" in {
75 | Get("/ingredients?donutName=plain%20donut&priceLevel=1.50") ~> donutRoutes ~> check {
76 | responseAs[String] shouldEqual "Received parameters: donutName=plain donut, priceLevel=1.5"
77 | status shouldEqual StatusCodes.OK
78 | }
79 | }
80 |
81 |
82 |
83 | "Check for wrong types being passed through to the priceLevel query param at /ingredients" in {
84 | Get("/ingredients?donutName=plain%20donut&priceLevel=cheap") ~> Route.seal(donutRoutes) ~> check {
85 | responseAs[String] shouldEqual """The query parameter 'priceLevel' was malformed:
86 | |'cheap' is not a valid 64-bit floating point value""".stripMargin
87 | status shouldEqual StatusCodes.BadRequest
88 | }
89 | }
90 |
91 |
92 |
93 | "Verify CSV parameters for /bake-donuts" in {
94 | Get("/bake-donuts?ingredients=flour,sugar,vanilla") ~> donutRoutes ~> check {
95 | responseAs[String] shouldEqual "Received CSV parameter: ingredients=List(flour, sugar, vanilla)"
96 | status shouldEqual StatusCodes.OK
97 | }
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/actors/Tutorial_10_Error_Kernel_Supervision.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.actors
2 |
3 | import akka.actor.SupervisorStrategy.{Escalate, Restart}
4 | import akka.actor._
5 | import akka.util.Timeout
6 |
7 | import scala.concurrent.Future
8 |
9 | /**
10 | * Created by Nadim Bahadoor on 28/06/2016.
11 | *
12 | * Tutorial: Learn How To Use Akka
13 | *
14 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
15 | *
16 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
17 | *
18 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
19 | * use this file except in compliance with the License. You may obtain a copy of
20 | * the License at
21 | *
22 | * [http://www.apache.org/licenses/LICENSE-2.0]
23 | *
24 | * Unless required by applicable law or agreed to in writing, software
25 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
26 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
27 | * License for the specific language governing permissions and limitations under
28 | * the License.
29 | */
30 | object Tutorial_10_Error_Kernel_Supervision extends App {
31 |
32 | println("Step 1: Create an actor system")
33 | val system = ActorSystem("DonutStoreActorSystem")
34 |
35 |
36 |
37 | println("\nStep 5: Define DonutStockActor")
38 | val donutStockActor = system.actorOf(Props[DonutStockActor], name = "DonutStockActor")
39 |
40 |
41 |
42 | println("\nStep 6: Akka Ask Pattern")
43 | import DonutStoreProtocol._
44 | import akka.pattern._
45 | import scala.concurrent.ExecutionContext.Implicits.global
46 | import scala.concurrent.duration._
47 | implicit val timeout = Timeout(5 second)
48 |
49 | val vanillaDonutStock: Future[Int] = (donutStockActor ? CheckStock("vanilla")).mapTo[Int]
50 | for {
51 | found <- vanillaDonutStock
52 | } yield (println(s"Vanilla donut stock = $found"))
53 |
54 | Thread.sleep(5000)
55 |
56 |
57 |
58 | println("\nStep 7: Close the actor system")
59 | val isTerminated = system.terminate()
60 |
61 |
62 |
63 |
64 | println("\nStep 2: Define the message passing protocol for our DonutStoreActor")
65 | object DonutStoreProtocol {
66 | case class Info(name: String)
67 |
68 | case class CheckStock(name: String)
69 |
70 | case class WorkerFailedException(error: String) extends Exception(error)
71 | }
72 |
73 |
74 | println("\nStep 3: Create DonutStockActor")
75 | class DonutStockActor extends Actor with ActorLogging {
76 |
77 | override def supervisorStrategy: SupervisorStrategy =
78 | OneForOneStrategy(maxNrOfRetries = 3, withinTimeRange = 1 seconds) {
79 | case _: WorkerFailedException =>
80 | log.error("Worker failed exception, will restart.")
81 | Restart
82 |
83 | case _: Exception =>
84 | log.error("Worker failed, will need to escalate up the hierarchy")
85 | Escalate
86 | }
87 |
88 | val workerActor = context.actorOf(Props[DonutStockWorkerActor], name = "DonutStockWorkerActor")
89 |
90 | def receive = {
91 | case checkStock @ CheckStock(name) =>
92 | log.info(s"Checking stock for $name donut")
93 | workerActor forward checkStock
94 | }
95 | }
96 |
97 |
98 |
99 | println("\nStep 4: Worker Actor called DonutStockWorkerActor")
100 | class DonutStockWorkerActor extends Actor with ActorLogging {
101 |
102 | @throws[Exception](classOf[Exception])
103 | override def postRestart(reason: Throwable): Unit = {
104 | log.info(s"restarting ${self.path.name} because of $reason")
105 | }
106 |
107 | def receive = {
108 | case CheckStock(name) =>
109 | findStock(name)
110 | context.stop(self)
111 | }
112 |
113 | def findStock(name: String): Int = {
114 | log.info(s"Finding stock for donut = $name")
115 | 100
116 | // throw new IllegalStateException("boom") // Will Escalate the exception up the hierarchy
117 | // throw new WorkerFailedException("boom") // Will Restart DonutStockWorkerActor
118 | }
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/fsm/Tutorial_09_AkkaFSM_PartSix.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.fsm
2 |
3 | import akka.actor.{LoggingFSM, PoisonPill, Props, ActorSystem}
4 |
5 | /**
6 | * Created by Nadim Bahadoor on 28/06/2016.
7 | *
8 | * Tutorial: Learn How To Use Akka
9 | *
10 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
11 | *
12 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
13 | *
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
15 | * use this file except in compliance with the License. You may obtain a copy of
16 | * the License at
17 | *
18 | * [http://www.apache.org/licenses/LICENSE-2.0]
19 | *
20 | * Unless required by applicable law or agreed to in writing, software
21 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23 | * License for the specific language governing permissions and limitations under
24 | * the License.
25 | */
26 | object Tutorial_09_AkkaFSM_PartSix extends App {
27 |
28 | println("Step 1: Create ActorSystem")
29 | val system = ActorSystem("DonutActorFSM")
30 |
31 |
32 |
33 | println("\nStep 6: Create DonutBakingActor")
34 | val bakingActor = system.actorOf(Props[DonutBakingActor], "donut-baking-actor")
35 |
36 |
37 |
38 | println("\nStep 7: Send events to actor to switch states and process events")
39 | bakingActor ! PoisonPill
40 | Thread.sleep(2000)
41 |
42 |
43 |
44 | println("\nStep 8: Shutdown actor system")
45 | system.terminate()
46 |
47 |
48 |
49 | println("\nStep 2: Defining events")
50 | sealed trait BakingEvents
51 | case object BakeDonut extends BakingEvents
52 | case object AddTopping extends BakingEvents
53 | case object StopBaking extends BakingEvents
54 |
55 |
56 |
57 | println("\nStep 3: Defining states")
58 | sealed trait BakingStates
59 | case object Start extends BakingStates
60 | case object Stop extends BakingStates
61 |
62 |
63 |
64 | println("\nStep 4: Defining mutatable data")
65 | case class BakingData(qty: Int) {
66 | def addOneDonut = copy(qty + 1)
67 | }
68 |
69 | object BakingData {
70 | def initialQuantity = BakingData(0)
71 | }
72 |
73 |
74 |
75 | println("\nStep 5: Define DonutBakingActor using LoggingFSM trait")
76 | class DonutBakingActor extends LoggingFSM[BakingStates, BakingData] {
77 | startWith(Stop, BakingData.initialQuantity)
78 |
79 | when(Stop) {
80 | case Event(BakeDonut, _) =>
81 | println("Current state is [Stop], switching to [Start]")
82 | goto(Start).using(stateData.addOneDonut)
83 |
84 | case Event(AddTopping, _) =>
85 | println("Current state is [Stop], you first need to move to [BakeDonut]")
86 | stay
87 | }
88 |
89 | import scala.concurrent.duration._
90 | when(Start, stateTimeout = 5 second) {
91 | case Event(StopBaking, _) =>
92 | println(s"Event StopBaking, current donut quantity = ${stateData.qty}")
93 | goto(Stop)
94 |
95 | case Event(StateTimeout, _) =>
96 | println("Timing out state = [Start], switching to state = [Stop]")
97 | goto(Stop)
98 | }
99 |
100 | whenUnhandled {
101 | case Event(event, stateData) =>
102 | println(s"We've received an unhandled event = [$event] for the state data = [$stateData]")
103 | goto(Stop)
104 | }
105 |
106 | onTransition {
107 | case Stop -> Start => println("Switching state from [Stop -> Start]")
108 | case Start -> Stop => println("Switching state from [Start -> Stop]")
109 | }
110 |
111 | import akka.actor.FSM._
112 | onTermination {
113 | case StopEvent(Normal, state, data) =>
114 | log.info(s"Actor onTermination, event = Normal, state = $state, data = $data")
115 |
116 | case StopEvent(Shutdown, state, data) =>
117 | log.info(s"Actor onTermination, event = Shutdown, state = $state, data = $data")
118 |
119 | case StopEvent(Failure(cause), state, data) =>
120 | log.error(s"Actor onTermination, event = Failure, cause = $cause, state = $state, data = $data")
121 | }
122 |
123 | initialize()
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/routers/Tutorial_04_BroadcastPoolRouter.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.routers
2 |
3 | import akka.actor.SupervisorStrategy.{Escalate, Restart}
4 | import akka.actor._
5 | import akka.routing.{BroadcastPool, DefaultResizer}
6 | import akka.util.Timeout
7 |
8 | /**
9 | * Created by Nadim Bahadoor on 28/06/2016.
10 | *
11 | * Tutorial: Learn How To Use Akka
12 | *
13 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
14 | *
15 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
16 | *
17 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
18 | * use this file except in compliance with the License. You may obtain a copy of
19 | * the License at
20 | *
21 | * [http://www.apache.org/licenses/LICENSE-2.0]
22 | *
23 | * Unless required by applicable law or agreed to in writing, software
24 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
25 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26 | * License for the specific language governing permissions and limitations under
27 | * the License.
28 | */
29 | object Tutorial_04_BroadcastPoolRouter extends App {
30 |
31 | println("Step 1: Create an actor system")
32 | val system = ActorSystem("DonutStoreActorSystem")
33 |
34 |
35 |
36 | println("\nStep 2: Define the message passing protocol for our DonutStoreActor")
37 | object DonutStoreProtocol {
38 | case class Info(name: String)
39 |
40 | case class CheckStock(name: String)
41 |
42 | case class WorkerFailedException(error: String) extends Exception(error)
43 | }
44 |
45 |
46 |
47 | println("\nStep 5: Define DonutStockActor")
48 | val donutStockActor = system.actorOf(Props[DonutStockActor], name = "DonutStockActor")
49 |
50 |
51 |
52 | println("\nStep 6: Use Akka Tell Pattern and send a single request to DonutStockActor")
53 | import DonutStoreProtocol._
54 | donutStockActor ! CheckStock("vanilla")
55 |
56 | Thread.sleep(5000)
57 |
58 |
59 |
60 | println("\nStep 7: Close the actor system")
61 | val isTerminated = system.terminate()
62 |
63 |
64 |
65 | println("\nStep 3: Create DonutStockActor")
66 | class DonutStockActor extends Actor with ActorLogging {
67 | import scala.concurrent.duration._
68 | implicit val timeout = Timeout(5 second)
69 |
70 | override def supervisorStrategy: SupervisorStrategy =
71 | OneForOneStrategy(maxNrOfRetries = 3, withinTimeRange = 5 seconds) {
72 | case _: WorkerFailedException =>
73 | log.error("Worker failed exception, will restart.")
74 | Restart
75 |
76 | case _: Exception =>
77 | log.error("Worker failed, will need to escalate up the hierarchy")
78 | Escalate
79 | }
80 |
81 | // We will not create a single worker actor.
82 | // val workerActor = context.actorOf(Props[DonutStockWorkerActor], name = "DonutStockWorkerActor")
83 |
84 | // We are using a resizable BroadcastPool.
85 | val workerName = "DonutStockWorkerActor"
86 | val resizer = DefaultResizer(lowerBound = 5, upperBound = 10)
87 | val props = BroadcastPool(
88 | nrOfInstances = 5,
89 | resizer = None,
90 | supervisorStrategy = supervisorStrategy
91 | ).props(Props[DonutStockWorkerActor])
92 |
93 | val donutStockWorkerRouterPool: ActorRef = context.actorOf(props, "DonutStockWorkerRouter")
94 |
95 | def receive = {
96 | case checkStock @ CheckStock(name) =>
97 | log.info(s"Checking stock for $name donut")
98 | donutStockWorkerRouterPool ! checkStock
99 | }
100 | }
101 |
102 |
103 |
104 | println("\ntep 4: Worker Actor called DonutStockWorkerActor")
105 | class DonutStockWorkerActor extends Actor with ActorLogging {
106 |
107 | override def postRestart(reason: Throwable): Unit = {
108 | log.info(s"restarting ${self.path.name} because of $reason")
109 | }
110 |
111 | def receive = {
112 | case CheckStock(name) =>
113 | sender ! findStock(name)
114 | }
115 |
116 | def findStock(name: String): Int = {
117 | log.info(s"Finding stock for donut = $name, thread = ${Thread.currentThread().getId}")
118 | 100
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/routers/Tutorial_01_RoundRobinPoolRouter.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.routers
2 |
3 | import akka.actor.SupervisorStrategy.{Escalate, Restart}
4 | import akka.actor._
5 | import akka.routing.{RoundRobinPool, DefaultResizer}
6 | import akka.util.Timeout
7 |
8 | import scala.concurrent.Future
9 |
10 | /**
11 | * Created by Nadim Bahadoor on 28/06/2016.
12 | *
13 | * Tutorial: Learn How To Use Akka
14 | *
15 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
16 | *
17 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
18 | *
19 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
20 | * use this file except in compliance with the License. You may obtain a copy of
21 | * the License at
22 | *
23 | * [http://www.apache.org/licenses/LICENSE-2.0]
24 | *
25 | * Unless required by applicable law or agreed to in writing, software
26 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
27 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
28 | * License for the specific language governing permissions and limitations under
29 | * the License.
30 | */
31 | object Tutorial_01_RoundRobinPoolRouter extends App {
32 |
33 |
34 | println("Step 1: Create an actor system")
35 | val system = ActorSystem("DonutStoreActorSystem")
36 |
37 |
38 |
39 | println("\nStep 5: Define DonutStockActor")
40 | val donutStockActor = system.actorOf(Props[DonutStockActor], name = "DonutStockActor")
41 |
42 |
43 |
44 | println("\nStep 6: Use Akka Ask Pattern and send a bunch of requests to DonutStockActor")
45 | import DonutStoreProtocol._
46 | import akka.pattern._
47 | import scala.concurrent.ExecutionContext.Implicits.global
48 | import scala.concurrent.duration._
49 | implicit val timeout = Timeout(5 second)
50 |
51 | val vanillaStockRequests = (1 to 10).map(i => (donutStockActor ? CheckStock("vanilla")).mapTo[Int])
52 | for {
53 | results <- Future.sequence(vanillaStockRequests)
54 | } yield println(s"vanilla stock results = $results")
55 |
56 | Thread.sleep(5000)
57 |
58 |
59 |
60 | val isTerminated = system.terminate()
61 |
62 |
63 |
64 | println("\nStep 2: Define the message passing protocol for our DonutStoreActor")
65 | object DonutStoreProtocol {
66 | case class Info(name: String)
67 |
68 | case class CheckStock(name: String)
69 |
70 | case class WorkerFailedException(error: String) extends Exception(error)
71 | }
72 |
73 |
74 |
75 | println("\nStep 3: Create DonutStockActor")
76 | class DonutStockActor extends Actor with ActorLogging {
77 |
78 | override def supervisorStrategy: SupervisorStrategy =
79 | OneForOneStrategy(maxNrOfRetries = 3, withinTimeRange = 5 seconds) {
80 | case _: WorkerFailedException =>
81 | log.error("Worker failed exception, will restart.")
82 | Restart
83 |
84 | case _: Exception =>
85 | log.error("Worker failed, will need to escalate up the hierarchy")
86 | Escalate
87 | }
88 |
89 | // We will not create one worker actor.
90 | // val workerActor = context.actorOf(Props[DonutStockWorkerActor], name = "DonutStockWorkerActor")
91 |
92 | // We are using a resizable RoundRobinPool.
93 | val resizer = DefaultResizer(lowerBound = 5, upperBound = 10)
94 | val props = RoundRobinPool(5, Some(resizer), supervisorStrategy = supervisorStrategy)
95 | .props(Props[DonutStockWorkerActor])
96 | val donutStockWorkerRouterPool: ActorRef = context.actorOf(props, "DonutStockWorkerRouter")
97 |
98 | def receive = {
99 | case checkStock @ CheckStock(name) =>
100 | log.info(s"Checking stock for $name donut")
101 | donutStockWorkerRouterPool forward checkStock
102 | }
103 | }
104 |
105 |
106 |
107 | println("\ntep 4: Worker Actor called DonutStockWorkerActor")
108 | class DonutStockWorkerActor extends Actor with ActorLogging {
109 |
110 | override def postRestart(reason: Throwable): Unit = {
111 | log.info(s"restarting ${self.path.name} because of $reason")
112 | }
113 |
114 | def receive = {
115 | case CheckStock(name) =>
116 | sender ! findStock(name)
117 | }
118 |
119 | def findStock(name: String): Int = {
120 | log.info(s"Finding stock for donut = $name, thread = ${Thread.currentThread().getId}")
121 | 100
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/routers/Tutorial_03_TailChoppingPool.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.routers
2 |
3 | import akka.actor.SupervisorStrategy.{Escalate, Restart}
4 | import akka.actor._
5 | import akka.routing.{TailChoppingPool, DefaultResizer}
6 | import akka.util.Timeout
7 |
8 | import scala.concurrent.Future
9 |
10 | /**
11 | * Created by Nadim Bahadoor on 28/06/2016.
12 | *
13 | * Tutorial: Learn How To Use Akka
14 | *
15 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
16 | *
17 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
18 | *
19 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
20 | * use this file except in compliance with the License. You may obtain a copy of
21 | * the License at
22 | *
23 | * [http://www.apache.org/licenses/LICENSE-2.0]
24 | *
25 | * Unless required by applicable law or agreed to in writing, software
26 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
27 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
28 | * License for the specific language governing permissions and limitations under
29 | * the License.
30 | */
31 | object Tutorial_03_TailChoppingPool extends App {
32 |
33 | println("Step 1: Create an actor system")
34 | val system = ActorSystem("DonutStoreActorSystem")
35 |
36 |
37 |
38 | println("\nStep 5: Define DonutStockActor")
39 | val donutStockActor = system.actorOf(Props[DonutStockActor], name = "DonutStockActor")
40 |
41 |
42 |
43 | println("\nStep 6: Use Akka Ask Pattern and send a bunch of requests to DonutStockActor")
44 | import DonutStoreProtocol._
45 | import akka.pattern._
46 |
47 | import scala.concurrent.ExecutionContext.Implicits.global
48 | import scala.concurrent.duration._
49 | implicit val timeout = Timeout(5 second)
50 |
51 | val vanillaStockRequests = (1 to 2).map(i => (donutStockActor ? CheckStock("vanilla")).mapTo[Int])
52 | for {
53 | results <- Future.sequence(vanillaStockRequests)
54 | } yield println(s"vanilla stock results = $results")
55 |
56 | Thread.sleep(5000)
57 |
58 |
59 |
60 | println("\nStep 2: Define the message passing protocol for our DonutStoreActor")
61 | object DonutStoreProtocol {
62 | case class Info(name: String)
63 |
64 | case class CheckStock(name: String)
65 |
66 | case class WorkerFailedException(error: String) extends Exception(error)
67 | }
68 |
69 |
70 |
71 | println("\nStep 3: Create DonutStockActor")
72 | class DonutStockActor extends Actor with ActorLogging {
73 |
74 | override def supervisorStrategy: SupervisorStrategy =
75 | OneForOneStrategy(maxNrOfRetries = 3, withinTimeRange = 5 seconds) {
76 | case _: WorkerFailedException =>
77 | log.error("Worker failed exception, will restart.")
78 | Restart
79 |
80 | case _: Exception =>
81 | log.error("Worker failed, will need to escalate up the hierarchy")
82 | Escalate
83 | }
84 |
85 | // We will not create a single worker actor.
86 | // val workerActor = context.actorOf(Props[DonutStockWorkerActor], name = "DonutStockWorkerActor")
87 |
88 | // We are using a resizable TailChoppingPool.
89 | val workerName = "DonutStockWorkerActor"
90 | val resizer = DefaultResizer(lowerBound = 5, upperBound = 10)
91 | val props = TailChoppingPool(
92 | nrOfInstances = 5,
93 | resizer = Some(resizer),
94 | within = 5 seconds,
95 | interval = 10 millis,
96 | supervisorStrategy = supervisorStrategy
97 | ).props(Props[DonutStockWorkerActor])
98 |
99 | val donutStockWorkerRouterPool: ActorRef = context.actorOf(props, "DonutStockWorkerRouter")
100 |
101 | def receive = {
102 | case checkStock @ CheckStock(name) =>
103 | log.info(s"Checking stock for $name donut")
104 | donutStockWorkerRouterPool forward checkStock
105 | }
106 | }
107 |
108 |
109 |
110 | println("\ntep 4: Worker Actor called DonutStockWorkerActor")
111 | class DonutStockWorkerActor extends Actor with ActorLogging {
112 |
113 | override def postRestart(reason: Throwable): Unit = {
114 | log.info(s"restarting ${self.path.name} because of $reason")
115 | }
116 |
117 | def receive = {
118 | case CheckStock(name) =>
119 | sender ! findStock(name)
120 | }
121 |
122 | def findStock(name: String): Int = {
123 | log.info(s"Finding stock for donut = $name, thread = ${Thread.currentThread().getId}")
124 | 100
125 | }
126 | }
127 |
128 | }
129 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/routers/Tutorial_02_ScatterGatherFirstCompletedPoolRouter.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.routers
2 |
3 | import akka.actor.SupervisorStrategy.{Escalate, Restart}
4 | import akka.actor._
5 | import akka.routing.{ScatterGatherFirstCompletedPool, DefaultResizer}
6 | import akka.util.Timeout
7 |
8 | import scala.concurrent.Future
9 |
10 | /**
11 | * Created by Nadim Bahadoor on 28/06/2016.
12 | *
13 | * Tutorial: Learn How To Use Akka
14 | *
15 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
16 | *
17 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
18 | *
19 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
20 | * use this file except in compliance with the License. You may obtain a copy of
21 | * the License at
22 | *
23 | * [http://www.apache.org/licenses/LICENSE-2.0]
24 | *
25 | * Unless required by applicable law or agreed to in writing, software
26 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
27 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
28 | * License for the specific language governing permissions and limitations under
29 | * the License.
30 | */
31 | object Tutorial_02_ScatterGatherFirstCompletedPoolRouter extends App {
32 |
33 | println("Step 1: Create an actor system")
34 | val system = ActorSystem("DonutStoreActorSystem")
35 |
36 |
37 |
38 | println("\nStep 5: Define DonutStockActor")
39 | val donutStockActor = system.actorOf(Props[DonutStockActor], name = "DonutStockActor")
40 |
41 |
42 |
43 | println("\nStep 6: Use Akka Ask Pattern and send a bunch of requests to DonutStockActor")
44 | import DonutStoreProtocol._
45 | import akka.pattern._
46 |
47 | import scala.concurrent.ExecutionContext.Implicits.global
48 | import scala.concurrent.duration._
49 | implicit val timeout = Timeout(5 second)
50 |
51 | val vanillaStockRequests = (1 to 2).map(i => (donutStockActor ? CheckStock("vanilla")).mapTo[Int])
52 | for {
53 | results <- Future.sequence(vanillaStockRequests)
54 | } yield println(s"vanilla stock results = $results")
55 |
56 | Thread.sleep(5000)
57 |
58 |
59 |
60 | println("\nStep 7: Close the actor system")
61 | val isTerminated = system.terminate()
62 |
63 |
64 |
65 | println("\nStep 2: Define the message passing protocol for our DonutStoreActor")
66 | object DonutStoreProtocol {
67 | case class Info(name: String)
68 |
69 | case class CheckStock(name: String)
70 |
71 | case class WorkerFailedException(error: String) extends Exception(error)
72 | }
73 |
74 |
75 |
76 | println("\nStep 3: Create DonutStockActor")
77 | class DonutStockActor extends Actor with ActorLogging {
78 |
79 | override def supervisorStrategy: SupervisorStrategy =
80 | OneForOneStrategy(maxNrOfRetries = 3, withinTimeRange = 5 seconds) {
81 | case _: WorkerFailedException =>
82 | log.error("Worker failed exception, will restart.")
83 | Restart
84 |
85 | case _: Exception =>
86 | log.error("Worker failed, will need to escalate up the hierarchy")
87 | Escalate
88 | }
89 |
90 | // We will not create a single worker actor.
91 | // val workerActor = context.actorOf(Props[DonutStockWorkerActor], name = "DonutStockWorkerActor")
92 |
93 | // We are using a resizable ScatterGatherFirstCompletedPool.
94 | val workerName = "DonutStockWorkerActor"
95 | val resizer = DefaultResizer(lowerBound = 5, upperBound = 10)
96 | val props = ScatterGatherFirstCompletedPool(
97 | nrOfInstances = 5,
98 | resizer = Some(resizer),
99 | supervisorStrategy = supervisorStrategy,
100 | within = 5 seconds
101 | ).props(Props[DonutStockWorkerActor])
102 |
103 | val donutStockWorkerRouterPool: ActorRef = context.actorOf(props, "DonutStockWorkerRouter")
104 |
105 | def receive = {
106 | case checkStock @ CheckStock(name) =>
107 | log.info(s"Checking stock for $name donut")
108 | // We forward any work to be carried by worker actors within the pool
109 | donutStockWorkerRouterPool forward checkStock
110 | }
111 | }
112 |
113 |
114 |
115 | println("\ntep 4: Worker Actor called DonutStockWorkerActor")
116 | class DonutStockWorkerActor extends Actor with ActorLogging {
117 |
118 | override def postRestart(reason: Throwable): Unit = {
119 | log.info(s"restarting ${self.path.name} because of $reason")
120 | }
121 |
122 | def receive = {
123 | case CheckStock(name) =>
124 | sender ! findStock(name)
125 | }
126 |
127 | def findStock(name: String): Int = {
128 | log.info(s"Finding stock for donut = $name, thread = ${Thread.currentThread().getId}")
129 | 100
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/source-code/learn-akka/src/main/scala/com/allaboutscala/learn/akka/http/routes/DonutRoute.scala:
--------------------------------------------------------------------------------
1 | package com.allaboutscala.learn.akka.http.routes
2 |
3 | import akka.http.scaladsl.model.{HttpResponse, StatusCodes}
4 | import akka.http.scaladsl.server.Directives._
5 | import akka.http.scaladsl.server.Route
6 | import akka.http.scaladsl.unmarshalling.Unmarshaller.identityUnmarshaller
7 | import com.allaboutscala.learn.akka.http.jsonsupport.{Donut, Donuts, JsonSupport}
8 | import com.typesafe.scalalogging.LazyLogging
9 |
10 | import scala.concurrent.Future
11 | import scala.util.{Failure, Success, Try}
12 |
13 | /**
14 | * Created by Nadim Bahadoor on 28/06/2016.
15 | *
16 | * Tutorial: Learn How To Use Akka HTTP
17 | *
18 | * [[http://allaboutscala.com/scala-frameworks/akka/]]
19 | *
20 | * Copyright 2016 Nadim Bahadoor (http://allaboutscala.com)
21 | *
22 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
23 | * use this file except in compliance with the License. You may obtain a copy of
24 | * the License at
25 | *
26 | * [http://www.apache.org/licenses/LICENSE-2.0]
27 | *
28 | * Unless required by applicable law or agreed to in writing, software
29 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
30 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
31 | * License for the specific language governing permissions and limitations under
32 | * the License.
33 | */
34 |
35 | final case class Ingredient(donutName: String, priceLevel: Double)
36 |
37 | class DonutRoutes extends JsonSupport with LazyLogging {
38 |
39 | val donutDao = new DonutDao()
40 |
41 | def route(): Route = {
42 | path("create-donut") {
43 | post {
44 | entity(as[Donut]) { donut =>
45 | logger.info(s"creating donut = $donut")
46 | complete(StatusCodes.Created, s"Created donut = $donut")
47 | }
48 | } ~ delete {
49 | complete(StatusCodes.MethodNotAllowed, "The HTTP DELETE operation is not allowed for the create-donut path.")
50 | }
51 | } ~ path("donuts") {
52 | get {
53 | onSuccess(donutDao.fetchDonuts()) { donuts =>
54 | complete(StatusCodes.OK, donuts)
55 | }
56 | }
57 | } ~ path("donuts-with-future-success-failure") {
58 | get {
59 | onComplete(donutDao.fetchDonuts()) {
60 | case Success(donuts) => complete(StatusCodes.OK, donuts)
61 | case Failure(ex) => complete(s"Failed to fetch donuts = ${ex.getMessage}")
62 | }
63 | }
64 | } ~ path("complete-with-http-response") {
65 | get {
66 | complete(HttpResponse(status = StatusCodes.OK, entity = "Using an HttpResponse object"))
67 | }
68 | } ~ path("donut-with-try-httpresponse") {
69 | get {
70 | val result: HttpResponse = donutDao.tryFetchDonuts().getOrElse(donutDao.defaultResponse())
71 | complete(result)
72 | }
73 | } ~ path("akka-http-failwith") {
74 | get {
75 | failWith(new RuntimeException("Boom"))
76 | }
77 | } ~ path("akka-http-getresource") {
78 | getFromResource("error-page.html")
79 | } ~ path("donuts" / Segment) { donutName =>
80 | get {
81 | val result = donutDao.donutDetails(donutName)
82 | onSuccess(result) { donutDetail =>
83 | complete(StatusCodes.OK, donutDetail)
84 | }
85 | }
86 | } ~ path("donuts" / "stock" / new scala.util.matching.Regex("""donut_[a-zA-Z0-9\-]*""")) { donutId =>
87 | get {
88 | complete(StatusCodes.OK, s"Looking up donut stock by donutId = $donutId")
89 | }
90 | } ~ path("donut" / "prices") {
91 | get {
92 | parameter("donutName") { donutName =>
93 | val output = s"Received parameter: donutName=$donutName"
94 | complete(StatusCodes.OK, output)
95 | }
96 | }
97 | } ~ path("donut" / "bake") {
98 | get {
99 | parameters('donutName, 'topping ? "sprinkles") { (donutName, topping) =>
100 | val output = s"Received parameters: donutName=$donutName and topping=$topping"
101 | complete(StatusCodes.OK, output)
102 | }
103 | }
104 | } ~ path("ingredients") {
105 | get {
106 | parameters('donutName.as[String], 'priceLevel.as[Double]) { (donutName, priceLevel) =>
107 | val output = s"Received parameters: donutName=$donutName, priceLevel=$priceLevel"
108 | complete(StatusCodes.OK, output)
109 | }
110 | }
111 | } ~ path("bake-donuts") {
112 | get {
113 | import akka.http.scaladsl.unmarshalling.PredefinedFromStringUnmarshallers.CsvSeq
114 | parameter('ingredients.as(CsvSeq[String])) { ingredients =>
115 | val output = s"Received CSV parameter: ingredients=$ingredients"
116 | complete(StatusCodes.OK, output)
117 | }
118 | }
119 | } ~ path("ingredients-to-case-class") {
120 | get {
121 | parameters('donutName.as[String], 'priceLevel.as[Double]).as(Ingredient) { ingredient =>
122 | val output = s"Encoded query parameters into case class, ingredient: $ingredient"
123 | complete(StatusCodes.OK, output)
124 | }
125 | }
126 | } ~ path("request-with-headers") {
127 | get {
128 | extractRequest { httpRequest =>
129 | val headers = httpRequest.headers.mkString(", ")
130 | complete(StatusCodes.OK, s"headers = $headers")
131 | }
132 | }
133 | } ~ path("multiple-segments" / Segments ) { segments =>
134 | get {
135 | val partA :: partB :: partC :: Nil = segments
136 | val output =
137 | s"""
138 | |Received the following Segments = $segments, with
139 | |partA = $partA
140 | |partB = $partB
141 | |partC = $partC
142 | """.stripMargin
143 | complete(StatusCodes.OK, output)
144 | }
145 | }
146 | }
147 | }
148 |
149 |
150 | class DonutDao {
151 | import scala.concurrent.ExecutionContext.Implicits.global
152 |
153 | val donutsFromDb = Vector(
154 | Donut("Plain Donut", 1.50),
155 | Donut("Chocolate Donut", 2),
156 | Donut("Glazed Donut", 2.50)
157 | )
158 |
159 | def fetchDonuts(): Future[Donuts] = Future {
160 | Donuts(donutsFromDb)
161 | }
162 |
163 | def tryFetchDonuts(): Try[HttpResponse] = Try {
164 | throw new IllegalStateException("Boom!")
165 | }
166 |
167 | def defaultResponse(): HttpResponse =
168 | HttpResponse(
169 | status = StatusCodes.NotFound,
170 | entity = "An unexpected error occurred. Please try again.")
171 |
172 | def donutDetails(donutName: String): Future[String] = Future {
173 | // this is obviously not as efficient as we're scanning a Vector by just one property of the Donut domain object.
174 | val someDonut = donutsFromDb.find(_.name == donutName)
175 | someDonut match {
176 | case Some(donut) => s"$donut"
177 | case None => s"Donut = $donutName was not found."
178 | }
179 | }
180 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Source Code For Scala Tutorials From http://allaboutscala.com/scala-frameworks/akka/
2 | ## Introduction
3 | The Scala programming language is rapidly growing in popularity! Sadly, most of the online tutorials do not provide a step-by-step guide :(
4 |
5 | At www.allaboutscala.com, we provide a complete beginner's tutorial to help you learn Scala in **small**, **simple** and **easy steps**.
6 |
7 | - Tutorials are organized such that they allow you to **learn gradually**.
8 | - Tutorials are written by taking into account the **complete beginner**.
9 | - Tutorials will make you proficient with the same professional **tools used by the Scala experts**.
10 |
11 | # Learn Akka
12 | - Code snippets for [Learn Akka](http://allaboutscala.com/scala-frameworks/akka/)
13 | - For additional details, please visit www.allaboutscala.com
14 |
15 | The examples below are the source code for Akka Tutorials from [allaboutscala.com](http://allaboutscala.com/scala-frameworks/akka/)
16 |
17 | # Introduction
18 | - [What is Akka](http://allaboutscala.com/scala-frameworks/akka/#what-is-akka)
19 | - [Project setup build.sbt](http://allaboutscala.com/scala-frameworks/akka/#project-setup-build-sbt)
20 |
21 | # Akka Actors
22 | - [Actor System Introduction](http://allaboutscala.com/scala-frameworks/akka/#actor-system-introduction)
23 | - [Tell Pattern](http://allaboutscala.com/scala-frameworks/akka/#tell-pattern)
24 | - [Ask Pattern](http://allaboutscala.com/scala-frameworks/akka/#ask-pattern)
25 | - [Ask Pattern mapTo](http://allaboutscala.com/scala-frameworks/akka/#ask-pattern-mapto)
26 | - [Ask Pattern pipeTo](http://allaboutscala.com/scala-frameworks/akka/#ask-pattern-pipeto)
27 | - [Actor Hierarchy](http://allaboutscala.com/scala-frameworks/akka/#actor-hierarchy)
28 | - [Actor Lookup](http://allaboutscala.com/scala-frameworks/akka/#actor-lookup)
29 | - [Child Actors](http://allaboutscala.com/scala-frameworks/akka/#child-actors)
30 | - [Actor Lifecycle](http://allaboutscala.com/scala-frameworks/akka/#actor-lifecycle)
31 | - [Actor PoisonPill](http://allaboutscala.com/scala-frameworks/akka/#actor-poisonpill)
32 | - [Error Kernel Supervision](http://allaboutscala.com/scala-frameworks/akka/#error-kernel-supervision)
33 |
34 | # Akka Routers
35 | - [RoundRobinPool](http://allaboutscala.com/scala-frameworks/akka/#roundrobinpool-router)
36 | - [ScatterGatherFirstCompletedPool](http://allaboutscala.com/scala-frameworks/akka/#scattergatherfirstcompletedpool-router)
37 | - [TailChoppingPool](http://allaboutscala.com/scala-frameworks/akka/#tailchoppingpool-router)
38 | - [BroadcastPool](http://allaboutscala.com/scala-frameworks/akka/#broadcastpool-router)
39 |
40 | # Akka Dispatchers
41 | - [Akka Default Dispatcher](http://allaboutscala.com/scala-frameworks/akka/#akka-default-dispatcher)
42 | - [Akka Lookup Dispatcher](http://allaboutscala.com/scala-frameworks/akka/#akka-lookup-dispatcher)
43 | - [Fixed Thread Pool Dispatcher](http://allaboutscala.com/scala-frameworks/akka/#fixed-thread-pool-dispatcher)
44 | - [Resizable Thread Pool Dispatcher](http://allaboutscala.com/scala-frameworks/akka/#resizable-thread-pool)
45 | - [Pinned Thread Pool Dispathcer](http://allaboutscala.com/scala-frameworks/akka/#pinned-thread-pool-dispatcher)
46 |
47 | # Akka FSM
48 | - [Actor FSM become()](http://allaboutscala.com/scala-frameworks/akka/#actor-fsm-become)
49 | - [Actor FSM unbecome()](http://allaboutscala.com/scala-frameworks/akka/#actor-fsm-unbecome)
50 | - [Actor FSM protocol](http://allaboutscala.com/scala-frameworks/akka/#actor-fsm-protocol)
51 | - [Actor LoggingFSM](http://allaboutscala.com/scala-frameworks/akka/#actor-fsm-loggingfsm)
52 | - [Actor LoggingFSM Part Two](http://allaboutscala.com/scala-frameworks/akka/#actor-fsm-loggingfsm-part-two)
53 | - [Actor LoggingFSM Part Three](http://allaboutscala.com/scala-frameworks/akka/#actor-fsm-loggingfsm-part-three)
54 | - [Actor LoggingFSM Part Four](http://allaboutscala.com/scala-frameworks/akka/#actor-fsm-loggingfsm-part-four)
55 | - [Actor LoggingFSM Part Five](http://allaboutscala.com/scala-frameworks/akka/#actor-fsm-loggingfsm-part-five)
56 | - [Actor LoggingFSM Part Six](http://allaboutscala.com/scala-frameworks/akka/#actor-fsm-loggingfsm-part-six)
57 | - [Actor FSM Scheduler](http://allaboutscala.com/scala-frameworks/akka/#actor-fsm-scheduler)
58 |
59 | # Akka TestKit
60 | - [Testing Actor FSM](http://allaboutscala.com/scala-frameworks/akka/#akka-testkit-test-actor-fsm)
61 | - [Testing Actor](http://allaboutscala.com/scala-frameworks/akka/#akka-testkit-test-actor)
62 | - [Testing Akka HTTP POST](http://allaboutscala.com/scala-frameworks/akka/#akka-testkit-http-post)
63 | - [Testing Query Parameter](http://allaboutscala.com/scala-frameworks/akka/#akka-testkit-query-parameter)
64 | - [Testing Required Query Parameter](http://allaboutscala.com/scala-frameworks/akka/#akka-testkit-required-query-parameter)
65 | - [Testing Optional Query Parameter](http://allaboutscala.com/scala-frameworks/akka/#akka-testkit-optional-query-parameter)
66 | - [Testing Typed Query Parameter](http://allaboutscala.com/scala-frameworks/akka/#akka-testkit-typed-query-parameter)
67 | - [Testing CSV Query Parameter](http://allaboutscala.com/scala-frameworks/akka/#akka-testkit-csv-query-parameter)
68 |
69 | # Akka HTTP
70 | - [Akka HTTP project setup build.sbt](http://allaboutscala.com/scala-frameworks/akka/#akka-http-project-setup-build-sbt)
71 | - [Start Akka HTTP Server](http://allaboutscala.com/scala-frameworks/akka/#akka-http-start-server)
72 | - [HTTP GET plain text](http://allaboutscala.com/scala-frameworks/akka/#akka-http-get-plain-text)
73 | - [HTTP GET JSON response](http://allaboutscala.com/scala-frameworks/akka/#akka-http-get-json-response)
74 | - [JSON encoding](http://allaboutscala.com/scala-frameworks/akka/#akka-http-json-encoding)
75 | - [JSON pretty print](http://allaboutscala.com/scala-frameworks/akka/#akka-http-json-pretty-print)
76 | - [HTTP POST JSON payload](http://allaboutscala.com/scala-frameworks/akka/#akka-http-post-json)
77 | - [Could not find implicit value](http://allaboutscala.com/scala-frameworks/akka/#akka-http-could-not-find-implicit-value)
78 | - [HTTP DELETE restriction](http://allaboutscala.com/scala-frameworks/akka/#akka-http-delete-method-restriction)
79 | - [Future onSuccess](http://allaboutscala.com/scala-frameworks/akka/#akka-http-future-onsuccess)
80 | - [Future onComplete](http://allaboutscala.com/scala-frameworks/akka/#akka-http-future-oncomplete)
81 | - [Complete with an HttpResponse](http://allaboutscala.com/scala-frameworks/akka/#akka-http-complete-httpresponse)
82 | - [Try failure using an HttpResponse](http://allaboutscala.com/scala-frameworks/akka/#akka-http-try-failure-httpresponse)
83 | - [Global rejection handler](http://allaboutscala.com/scala-frameworks/akka/#akka-http-global-rejection-handler)
84 | - [Global exception handler](http://allaboutscala.com/scala-frameworks/akka/#akka-http-global-exception-handler)
85 | - [Load HTML from resources](http://allaboutscala.com/scala-frameworks/akka/#akka-http-load-html-resource)
86 | - [RESTful URLs with segment](http://allaboutscala.com/scala-frameworks/akka/#akka-http-rest-url-segment)
87 | - [RESTful URLS with regex](http://allaboutscala.com/scala-frameworks/akka/#akka-http-rest-url-regex)
88 | - [RESTful URLS with multiple segments](http://allaboutscala.com/scala-frameworks/akka/#akka-http-multiple-segments)
89 | - [Query parameter](http://allaboutscala.com/scala-frameworks/akka/#akka-http-query-parameter)
90 | - [Optional query parameter](http://allaboutscala.com/scala-frameworks/akka/#akka-http-optional-query-parameter)
91 | - [Typed query parameters](http://allaboutscala.com/scala-frameworks/akka/#akka-http-typed-query-parameters)
92 | - [CSV query parameter](http://allaboutscala.com/scala-frameworks/akka/#akka-http-csv-query-parameter)
93 | - [Query parameter to case class](http://allaboutscala.com/scala-frameworks/akka/#akka-http-query-parameter-to-case-class)
94 | - [HTTP request headers](http://allaboutscala.com/scala-frameworks/akka/#akka-http-request-headers)
95 | - [HTTP client GET](http://allaboutscala.com/scala-frameworks/akka/#akka-http-client-get)
96 | - [Unmarshal HttpResponse to case class](http://allaboutscala.com/scala-frameworks/akka/#akka-http-unmarshal-case-class)
97 | - [HTTP client POST JSON](http://allaboutscala.com/scala-frameworks/akka/#akka-http-client-post-json)
98 |
99 | Stay in touch via [LinkedIn](https://linkedin.com/in/nadimbahadoor/), [Facebook](http://www.facebook.com/allaboutscala) and [Twitter](https://twitter.com/NadimBahadoor) for upcoming tutorials!
100 |
101 | ## Contact
102 | Nadim Bahadoor at http://allaboutscala.com/contact/
103 |
104 | ## License
105 | Apache 2.0 License - see the LICENSE.TXT file
106 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------