├── .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 | --------------------------------------------------------------------------------