Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

add scala syntax

  • Loading branch information...
commit 78ef1bee1d7967058fe950a678f51139c78eecba 1 parent 3f05add
@bleything authored
View
1  README.rdoc
@@ -45,6 +45,7 @@ Aaaaaalso, some syntax definitions:
* {Markdown}[http://github.com/ujihisa/vim-markdown]
* {nginx}[http://www.vim.org/scripts/script.php?script_id=1886]
* {RDoc}[http://www.vim.org/scripts/script.php?script_id=2878]
+* {Scala}[https://github.com/derekwyatt/vim-scala]
* {Slidedown}[http://www.vim.org/scripts/script.php?script_id=3069]
* {Textile}[http://www.vim.org/scripts/script.php?script_id=2305]
* {VCL}[https://github.com/smerrill/vcl-vim-plugin]
View
1  Rakefile
@@ -36,6 +36,7 @@ namespace :update do
:syntax_haml_sass => "git://github.com/tpope/vim-haml.git",
:syntax_markdown => "git://github.com/ujihisa/vim-markdown.git",
:syntax_rdoc => "git://github.com/depuracao/vim-rdoc.git",
+ :syntax_scala => "git://github.com/derekwyatt/vim-scala.git",
:syntax_slidedown => "git://github.com/bleything/vim-slidedown.git",
:syntax_textile => "git://github.com/timcharper/textile.vim.git",
:syntax_vcl => "git://github.com/smerrill/vcl-vim-plugin.git",
View
6 bundle/syntax_scala/.gitignore
@@ -0,0 +1,6 @@
+# Ignore Vim tag files
+tags
+
+# Ignore Vim swap files
+.*.swp
+.*.swo
View
12 bundle/syntax_scala/README
@@ -0,0 +1,12 @@
+This is a "bundle" for Vim that builds off of the initial Scala plugin modules
+by Stefan Matthias Aust and adds some more "stuff" that I find useful, including
+all of my notes and customizations.
+
+It's free for anyone to fork, clone, etc... no licensing or whatever... just do
+whatever you want with it, but you can't take credit for my stuff :)
+
+You really should be using Tim Pope's Pathogen module for Vim
+(https://github.com/tpope/vim-pathogen and
+http://tammersaleh.com/posts/the-modern-vim-config-with-pathogen) if you're
+going to clone this repository because, well... you should.
+
View
52 bundle/syntax_scala/after/plugin/help.vim
@@ -0,0 +1,52 @@
+
+function! FixTOCLine(beginning, colonCol)
+ let l = strlen(a:beginning)
+ let c = 0
+ let dots = ""
+ while c < (a:colonCol - l)
+ let dots = dots . "."
+ let c += 1
+ endwhile
+ return (a:beginning . dots . ":")
+endfunction
+
+function! BuildTOC()
+ let lnum = getpos(".")[1]
+ call append(lnum - 1, "<<<")
+ call append(lnum, ">>>")
+ :g/^\d\+\./co/>>>/-
+ :g/^<<</,/^>>>/s/ {{{\d\s*//
+ :g/^<<</,/^>>>/s/\*/|/g
+ :g/^<<</,/^>>>/s/^\ze\d\.\d\+\./ /
+ :g/^<<</,/^>>>/s/^\ze\d\d\.\d\+\./ /
+ :g/^<<</,/^>>>/s/^\ze\d\.\d\+/ /
+ :g/^<<</,/^>>>/s/^\ze\d\d\.\d\+/ /
+ :g/^<<</,/^>>>/s/^\ze\d\./ /
+ :g/^<<</,/^>>>/s/^\ze\d\d\./ /
+ :g/^\s\+0\. Content/d
+ :g/<<</+,/>>>/-s/^\(.\{-}\)\(\s\+\)\ze |/\=FixTOCLine(submatch(1), 45)/
+ :g/<<</d
+ :g/>>>/d
+endfunction
+
+command! BuildNewTableOfContents silent! call BuildTOC()
+
+function! JustifyCurrentLine()
+ let cline = getline('.')
+ let matches = matchlist(cline, '^\(.*\)\s\+\(\*.*\)$')
+ let st = matches[1]
+ let fin = matches[2]
+ let spcnum = 78 - strlen(st) - strlen(fin)
+ let c = 0
+ let spcs = ""
+ while c < spcnum
+ let spcs = spcs . " "
+ let c = c + 1
+ endwhile
+ let newline = st . spcs . fin
+ :norm dd
+ let lnum = getpos('.')[1]
+ call append(lnum - 1, newline)
+endfunction
+
+nmap ,jt :call JustifyCurrentLine()<cr>
View
4 bundle/syntax_scala/after/syntax/help.vim
@@ -0,0 +1,4 @@
+let b:current_syntax = ''
+unlet b:current_syntax
+syntax include @ScalaCode syntax/scala.vim
+syntax region rgnScala matchgroup=Ignore concealends start='!sc!' end='!/sc!' contains=@ScalaCode
View
1,981 bundle/syntax_scala/doc/akka_info.txt
@@ -0,0 +1,1981 @@
+*akkainfo.txt* Akka Reference and Information Feb 21, 2011
+
+Author: Derek Wyatt <derek@{my first name}{my last name}.org>
+
+Copyright: (c) 2011 by Derek Wyatt
+ No license implied... use it for whatever tickles your particular
+ fancy.
+
+==============================================================================
+0. Contents *akka* *akka-contents*
+------------------------------------------------------------------------------
+
+ 1. Manifesto...............................: |akka-manifesto|
+ 1.3 Core Services........................: |akka-core-services|
+ 1.4 Deployed Use Cases...................: |akka-deploy-use-cases|
+ 1.2 Scalability..........................: |akka-scalability|
+ 1.2 Fault-tolerance......................: |akka-fault-tolerance|
+ 2. Actors..................................: |akka-actors|
+ 2.1 Actor Lifecycle......................: |akka-actor-lifecycle|
+ 2.2 Actor Companion Object...............: |akka-actor-object|
+ 2.3 Defining by Derivation...............: |akka-actor-derive|
+ 2.4 Anonymous Creation...................: |akka-actor-anonymous|
+ 2.5 Actor vs. ActorRef...................: |akka-actor-actorref|
+ 2.6 !, !!, and !!!.......................: |akka-actor-send-message|
+ 2.6.1 !................................: |akka-actor-!|
+ 2.6.2 !!...............................: |akka-actor-!!|
+ 2.6.3 !!!..............................: |akka-actor-!!!|
+ 2.6.4 Unifying Pattern.................: |akka-actor-unifying-msg|
+ 2.6.5 Forwarding a Future..............: |akka-actor-future-fwd|
+ 2.7 Actor Control........................: |akka-actor-control|
+ 2.7.1 Starting and Stopping............: |akka-actor-start-stop|
+ 2.7.2 Poison Pill......................: |akka-actor-poisonpill|
+ 2.7.3 Actor Murder.....................: |akka-actor-murder|
+ 2.8 Hot-Swapping.........................: |akka-actor-hotswap|
+ 2.8.1 Invoking the Hot-Swap............: |akka-actor-invoke-hotswap|
+ 2.8.2 Reverting the Hot-Swap...........: |akka-actor-revert-hotswap|
+ 2.9 PartialFunction Chaining.............: |akka-actor-partialfunc-chaining|
+ 2.10 Actor Registry......................: |akka-actor-registry|
+ 2.11 Remote Actors.......................: |akka-actor-remote|
+ 2.11.1 Starting Up Remote..............: |akka-actor-remote-startup|
+ 2.11.2 Registering Actors..............: |akka-actor-remote-register|
+ 2.11.3 Invoking Actors Remotely........: |akka-actor-remote-invoke|
+ 2.11.4 Connection Fault Tolerance......: |akka-actor-remote-resilience|
+ 2.11.5 Remote Security.................: |akka-actor-remote-security|
+ 2.11.6 Session Based Servers...........: |akka-actor-remote-sessions|
+ 2.11.7 Event Listening.................: |akka-actor-remote-events|
+ 2.11.8 Messge Serialization............: |akka-actor-remote-serialization|
+ 2.12 Scheduler...........................: |akka-actor-scheduler|
+ 2.13 Mailboxes...........................: |akka-actor-mailboxes|
+ 2.13.1 Viktor's Priority Mailbox.......: |akka-priority-mailbox|
+ 3. Actor Supervision.......................: |akka-supervision|
+ 3.1 So Why Not Just Use Erlang/OTP?......: |akka-why-not-erlang|
+ 3.2 Designing for Failure................: |akka-design-for-failure|
+ 3.3 Setting Up Supervision...............: |akka-setting-up-supervision|
+ 3.3.1 Fault Handling Strategies........: |akka-fault-handling-strategies|
+ 3.3.2 Restart LifeCycles...............: |akka-restart-lifecycles|
+ 3.3.3 Declarative Setup................: |akka-supervision-declarative-setup|
+ 3.3.3.1 Declarative Example............: |akka-supervision-declarative-example|
+ 3.3.4 Programmatic Setup...............: |akka-supervision-programmatic-setup|
+ 3.3.5 Getting Your Supervisor..........: |akka-supervision-getting-supervisor|
+ 3.3.6 Chained Restarts.................: |akka-supervision-chained-restarts|
+ 3.4 Non-Blocking Failure.................: |akka-non-blocking-failure|
+ 4. Actor Routing...........................: |akka-routing|
+ 4.1 Simple Dispatching...................: |akka-routing-dispatching|
+ 4.2 Simple Load Balancing................: |akka-routing-loadbalance|
+ 4.3 Actor Pools..........................: |akka-routing-pools|
+ 5. Cloudy Akka.............................: |akka-cloudy-akka|
+
+==============================================================================
+1. Manifesto *akka-manifesto* {{{1
+------------------------------------------------------------------------------
+
+Akka (http://akka.io) was created to focus on solving specific problems with
+building applications. The problem:
+
+ It's way too hard to build:
+ 1. Correctly, highly concurrent systems
+ 2. Truly scalable systems
+ 3. Fault-tolerant systems that self heal
+
+ ... using "state-of-the-art" tools
+
+The vision is to provide a single unified Programming Model and Runtime
+Service. Jonas specifically avoids the use of "Framework" here in order to
+try and avoid some of the notions that come along with that word -
+specifically the concept of being 'boxed in' to a programming style or some
+other type of rigid concept. The idea of a "toolkit" is much more applicable
+here.
+
+Akka claims to provide the ability to "transparently"
+
+ - scale up and out
+ - load balance
+ - handle failures
+ - provide remoting
+ - provide java and scala interfaces
+
+Akka specifically does not promote notions of shared state for concurrency and
+is designed from the ground up to use message-based concurrency.
+
+
+1.3 Core Services *akka-core-services* {{{2
+------------------------------------------------------------------------------
+
+"Concurrency"
+
+ - Actors
+ - Software Transactional Memory (STM)
+ - Agents
+ - Dataflow
+
+"Scalability"
+
+"Fault-tolerance"
+
+
+1.4 Deployed Use Cases *akka-deploy-use-cases* {{{2
+------------------------------------------------------------------------------
+
+Akka is being used in the following use cases (although these aren't backed up
+by the actual deployed sites, by name):
+
+Finance
+
+ - Stock trend Analysis & Simulation
+ - Event-driven messaging systems
+
+Betting and Gaming
+
+ - Massive multiplayer online gaming
+ - High throughput and transactional betting
+
+Telecom
+
+ - Streaming media network gateways
+
+Simulation
+
+ - 3D simluation engines
+
+E-Commerce
+
+ - Social media community sites
+
+
+1.2 Scalability *akka-scalability* {{{2
+------------------------------------------------------------------------------
+
+Akka aims to handle system overload by both scaling up (utilizing multiple
+cores) and scaling out (utlizing multiple nodes).
+
+1.2 Fault-tolerance *akka-fault-tolerance* {{{2
+------------------------------------------------------------------------------
+
+==============================================================================
+2. Actors *akka-actors* {{{1
+------------------------------------------------------------------------------
+
+The Actor Model has the following, arguable, benefits:
+
+ - Easier to reason about
+ - Raised abstraction level
+ - Easier to avoid:
+ - Race conditions
+ - Deadlocks
+ - Live locks
+ - Starvations
+
+There are typed and untyped Actors. At this time, I've only ever dealt with
+untyped Actors but, of course untyped entities are both a blessing and a
+curse, so while I've gone a long with the untyped Actors I will eventually
+need to investigate typed Actors.
+
+
+2.1 Actor Lifecycle *akka-actor-lifecycle* {{{2
+------------------------------------------------------------------------------
+
+NEW (newly created actor) - can't receive messages (yet)
+ => STARTED (when 'start' is invoked) - can receive messages
+ => SHUT DOWN (when 'exit' or 'stop' is invoked) - can't do anything
+
+
+2.2 Actor Companion Object *akka-actor-object* {{{2
+------------------------------------------------------------------------------
+
+The {Actor} object provides some convenience methods for constructing some
+"stuff":
+
+actorOf(factory => Actor): ActorRef *akka-actor-actorOf1*
+ Creates an ActorRef out of the Actor. Allows you to pass in a factory
+ function that creates the Actor. Please note that this function can be
+ invoked multiple times if for example the Actor is supervised and needs to
+ be restarted.
+
+ This function should NOT be used for remote actors.
+!sc!
+ import Actor._
+ val actor = actorOf(new MyActor)
+ actor.start
+ actor ! message
+ actor.stop
+!/sc!
+ You can create and start the actor in one statement like this:
+!sc!
+ val actor = actorOf(new MyActor).start!/sc!
+
+actorOf(clazz: Class[_ <: akka.actor.Actor]): ActorRef *akka-actor-actorOf2*
+ Creates an ActorRef out of the Actor of the specified Class.
+!sc!
+ import Actor._
+ val actor = actorOf(classOf[MyActor])
+ actor.start
+ actor ! message
+ actor.stop
+!/sc!
+ You can create and start the actor in one statement like this:
+!sc!
+ val actor = actorOf(classOf[MyActor]).start!/sc!
+
+ *akka-actor-actorOf3*
+actorOf[T <: Actor](implicit arg0: Manifest[T]): ActorRef
+ Creates an ActorRef out of the Actor with type T.
+!sc!
+ import Actor._
+ val actor = actorOf[MyActor]
+ actor.start
+ actor ! message
+ actor.stop
+!/sc!
+ You can create and start the actor in one statement like this:
+!sc!
+ val actor = actorOf[MyActor].start!/sc!
+
+{val} log : Logger *akka-actor-log*
+ This is merely a {val} which will will return the contextual SLF4J logger.
+
+{val} registry : ActorRegistry *akka-actor-registry-short*
+ This value contains the current {ActorRegistry} against which we can
+ register and lookup different {Actor}s. I can't find the code for this at
+ the moment, so I'm not sure if it's actually {Actor}s or {ActorRef}s -
+ probably the latter.
+
+{lazy} {val} remote : RemoteSupport *akka-actor-remote-short*
+ Provides access to the remoting system support for launching and accessing
+ remote {Actor}s
+
+ *akka-actor-spawn*
+spawn(body: => Unit)(implicit dispatcher: MessageDispatcher = ...) : Unit
+ Use to spawn out a block of code in an event-driven actor. Will shut actor
+ down when the block has been executed.
+
+ NOTE: If used from within an Actor then has to be qualified with
+ {Actor.spawn} since there is a method {spawn[ActorType]} in the Actor
+ trait already. Example:
+!sc!
+ import Actor.{spawn}
+ spawn {
+ ... // do stuff
+ }
+!/sc!
+2.3 Defining by Derivation *akka-actor-derive* {{{2
+------------------------------------------------------------------------------
+!sc!
+ scala> import akka.actor._
+ scala> import akka.actor.Actor._
+ scala> class MyActor extends Actor {
+ | def receive = {
+ | case "hithere" =>
+ | println("Well, hello there")
+ | }
+ | }
+ defined class MyActor
+
+ scala> var a = actorOf[MyActor].start
+
+ scala> a ! "hithere"
+ Well, hello there
+
+ scala> a.stop
+!/sc!
+
+2.4 Anonymous Creation *akka-actor-anonymous* {{{2
+------------------------------------------------------------------------------
+!sc!
+ scala> var a = actorOf(new Actor {
+ | def receive = {
+ | case "bite me" => println("NO! Bite _ME_!")
+ | }
+ | })
+ a: akka.actor.ActorRef = Actor[$anonfun$1$$anon$1:8c65a3d0-4379-11e0-9c39-005056c00008]
+
+ scala> a ! "bite me"
+ NO! Bite _ME_!
+
+ scala> a.stop
+!/sc!
+
+2.5 Actor vs. ActorRef *akka-actor-actorref* {{{2
+------------------------------------------------------------------------------
+
+One derives from {Actor} but the meat of things happens in the {ActorRef}, due
+to the fact (I assume at this point) that the {ActorRef} provides the
+mechanisms behind |akka-hotswap| and |akka-fault-tolerance|. By divorcing the
+implementation from the invocation, Akka can provide more execution framework
+aspects that you no longer need to worry about.
+
+The {actorOf} factory method available on the |akka-actor-object| provides the
+ability to get an {ActorRef} from a derivation of {Actor}.
+
+The {Actor} trait itself has very little in it and is really only there to
+give us a few points of extension:
+
+receive()
+
+ The point of entry for incoming messages - this is the
+ message handler that gets called when someone makes a
+ call to:
+ - ! (|akka-actor-!|)
+ - !! (|akka-actor-!!|)
+ - !!! (|akka-actor-!!!|)
+
+preStart()
+
+ Called before {Actor.start} (or {ActorRef.start}) is
+ called. Used to setup stuff before the /first/ call.
+
+postStop()
+
+ Called before the {Actor} is stopped. This can happen
+ in a few different ways so it's not specifically called
+ before a call to {Actor.stop}.
+
+preRestart()
+
+ Called before the {Actor} is restarted. When a supervisor
+ restarts the Actor, it will first call this method to
+ allow it to clear up some state first.
+
+postRestart()
+
+ Called after the {Actor} is restarted. This might let you
+ get something going again after the core system is up and
+ running.
+
+If you need access to the stuff held in the {self} field, you can import the
+members directly, if you want:
+!sc!
+ class MyActor extends Actor {
+ import self._
+ id = ...
+ dispatcher = ...
+ start
+ ...
+ }
+!/sc!
+
+2.6 !, !!, and !!! *akka-actor-send-message* {{{2
+------------------------------------------------------------------------------
+
+Actors are all about passing messages around and the !, !! and !!! methods are
+the {Actor}'s mechanisms for passing messages.
+
+2.6.1 ! *akka-actor-!* {{{3
+------------------------------------------------------------------------------
+
+The simple ! message is the best way to send something - it's the one-way
+fire-and-forget message that demands full asynchrony. Obviously if you only
+need a one-way message with no confirmation of delivery, you're fine just
+sending it any never thinking about it again. If, on the other hand, this
+one-way message is actually part of a multi-message conversation, you need to
+have some way of getting things back.
+
+The most reliable way of doing this to demand an {ActorRef} as a parameter on
+the message.
+!sc!
+ scala> case class GreetRequest(greeting: String, replyTo: ActorRef)
+ defined class GreetRequest
+
+ scala> case class GreetResponse(greeting: String)
+ defined class GreetResponse
+
+ scala> class ServerActor extends Actor {
+ | def receive = {
+ | case GreetRequest(greeting, replyTo) =>
+ | replyTo ! GreetResponse("You said, '" + greeting +
+ | "', and I say 'Thanks'")
+ | }
+ | }
+
+ scala> class ClientActor extends Actor {
+ | def receive = {
+ | case GreetResponse(greeting) =>
+ | println(greeting)
+ | }
+ | }
+ defined class ClientActor
+
+ scala> var server = actorOf[ServerActor].start
+ server: akka.actor.ActorRef = Actor[ServerActor:2d95a200-4384-11e0-9c39-005056c00008]
+
+ scala> var client = actorOf[ClientActor].start
+ client: akka.actor.ActorRef = Actor[ClientActor:34f5c160-4384-11e0-9c39-005056c00008]
+
+ scala> server ! GreetRequest("Hithere, ServerActor", client)
+ You said, 'Hithere, ServerActor', and I say 'Thanks'
+
+ scala> client.stop
+
+ scala> server.stop
+!/sc!
+You could also do this by using the {implicit} {sender}, contained inside the
+{self.sender} field, but you always have to be wary of whether or not the
+object that sent the message was actually an {Actor} or not. The type of the
+{self.sender} is {Option[AnyRef]}, which allows for the notion that the
+{sender} is not an {Actor}. So you have to keep checking it, and if your code
+would always like to see one there, then it's easiest to simply force it in
+the message and then it's there all the time.
+
+
+2.6.2 !! *akka-actor-!!* {{{3
+------------------------------------------------------------------------------
+
+The !! method is a blocking call. The implication is that the reciever is
+going to use the {self.reply} method in order to send a result to the caller.
+The caller is going to wait on a {Future} explicitly and get back an
+{Option[Any]} object in return. If the call did not time out then the
+{Option} will be a {Some} that actually contains the result and {None}
+otherwise.
+
+There are a couple of things to note here:
+
+- Blocking is bad...
+- ... but so is not getting a result and not knowing that
+
+The virtue of the !! method is that you'll know if something timed out. If,
+on the other hand you use the ! method and expect to be called back later, you
+need some mechanism to ensure that you are actually called back. Nobody's
+going to tell you something timed out because the timing out is part of the
+business logic, not the framework.
+
+NOTE: I'm expecting Akka to help out here. The fault tolerance in the system
+based on {Supervisor}s should be able to buy us - not necessarily guaranteed
+delivery - enough information in the system that lets us know when something
+croaked while still maintaining fully asynchrony.
+!sc!
+ scala> case class SyncGreetRequest(greeting: String)
+ defined class SyncGreetRequest
+
+ scala> class SyncServerActor extends Actor {
+ | def receive = {
+ | case SyncGreetRequest(greeting) =>
+ | self.reply("You said, '" + greeting + "', and I say 'Thanks'")
+ | }
+ | }
+ defined class SyncServerActor
+
+ scala> case class Go(server: ActorRef)
+ defined class Go
+
+ scala> class SyncClientActor extends Actor {
+ | def receive = {
+ | case Go(server) =>
+ | println((server !! SyncGreetRequest("Hithere, SyncServerActor")).get)
+ | }
+ | }
+ defined class SyncClientActor
+
+ scala> var client = actorOf[SyncClientActor].start
+ client: akka.actor.ActorRef = Actor[SyncClientActor:28fb2af0-4387-11e0-9c39-005056c00008]
+
+ scala> client ! Go(server)
+ You said, 'Hithere, SyncServerActor', and I say 'Thanks'
+!/sc!
+Note above that I simply call {get} on the {Option[Any]} I receive simply
+because it's easy, but we have to remember that it is an {Option} object, so
+it may not be valid to do that.
+
+
+2.6.3 !!! *akka-actor-!!!* {{{3
+------------------------------------------------------------------------------
+
+The !!! method returns a {Future}. This is a non-blocking call but requires
+the management of the {Future} and possibly turns things into a degenerate
+polling mechanism as a result.
+
+There is a plus side here, though... the caller that receives the {Future}
+need not be an {Actor}, as is the case in the !! call. Using the exact same
+{SyncServerActor} defined above, we have:
+!sc!
+ scala> val future = server !!! SyncGreetRequest("Hithere, SyncServerActor")
+ future: akka.dispatch.Future[Nothing] =
+ akka.dispatch.DefaultCompletableFuture@bf3fd22
+
+ scala> future.result
+ res16: Option[Nothing] =
+ Some(You said, 'Hithere, SyncServerActor', and I say 'Thanks')
+!/sc!
+
+2.6.4 Unifying Pattern *akka-actor-unifying-msg* {{{3
+------------------------------------------------------------------------------
+
+Ideally we should be able to unify the !, !!, !!! usage into a single pattern,
+where the client can choose to do a request / response interaction via the
+"scalable" ! or by the "deterministic" !!, or !!!. This is a non-general
+pattern that can use some work to generalize a bit more with some generics:
+!sc!
+ import akka.actor._
+ import akka.actor.Actor._
+
+ case class Request(msg: String, replyTo: ActorRef = null)
+ case class Response(msg: String)
+ case class SendRequestTo(msg: String, actor: ActorRef)
+
+ class Server extends Actor {
+ def receive = {
+ case Request(msg, replyTo) =>
+ if (replyTo == null)
+ self.reply(msg + " : dood")
+ else
+ replyTo ! Response(msg + " : dood")
+ }
+ }
+
+ class Client extends Actor {
+ def receive = {
+ case Response(msg) =>
+ println("Client got -> " + msg)
+ case SendRequestTo(msg, actor) =>
+ actor ! Request(msg, self)
+ }
+ }
+
+ scala> val server = actorOf[Server].start
+ scala> val client = actorOf[Client].start
+
+ scala> server !! Request("Waiting on Future")
+ res0: Option[Nothing] = Some(Waiting on a future : dood)
+
+ scala> val future = server !!! Request("Getting back a Future")
+ scala> future.result
+ res1: Option[Nothing] = Some(Getting back a Future : dood)
+
+ scala> client ! SendRequestTo("Hithere", server)
+ Client got -> Hithere : dood
+!/sc!
+
+2.6.5 Forwarding a Future *akka-actor-future-fwd* {{{3
+------------------------------------------------------------------------------
+
+There are times when we may want to synchronize an asynchronous call.
+i.e. something like this:
+ +---> SomeOtherActor ! AsyncReq
+ |
+ [Client] SomeActor !!! Msg -> [SomeActor] <-->
+ |
+ +<--- AsyncRsp ! SomeActor
+
+Or, in words...
+
+ - [Client] wants to send !! or !!! to [SomeActor] for {Msg}
+
+ - [SomeActor] could furnish that request, but unfortunately it's using
+ [SomeOtherActor] and the only mechanism it has with [SomeOtherActor] is an
+ asynchronous one.
+
+ - We need some way to give results to the {Future} object held by [Client]
+ over an asynchronous bridge.
+
+We can do that with the following:
+!sc!
+ class SomeOtherActor extends Actor {
+ def receive = {
+ // Inherently asynchronous
+ case AsyncReq =>
+ self.sender.get ! AsyncRsp("Here's some results")
+ }
+ }
+
+ class SomeActor extends Actor {
+ val server = actorOf[SomeOtherActor].start
+ def receive = {
+ // The Client wants this to be Future-based
+ case GetSomethingForMe =>
+ // - Delegate the "senderFuture" to this temporary Actor.
+ // - Create a closure, holding the future object for later use.
+ // - Call the "server" and send the intended request and receive that
+ // one message.
+ // - Once it's received, complete the future with the results and
+ // terminate yourself
+ actorOf(new { val future = self.senderFuture.get } with Actor {
+ def receive = {
+ case AsyncRsp(results) =>
+ future.completeWithResult(results)
+ self.stop
+ // It's very important to do this. I previously had the call
+ // to "server ! AsyncReq" in the constructor of this anonymous
+ // Actor but that causes a race condition. The call back to
+ // this Actor's AsyncRsp(results) handler is called before the
+ // 'start' call below completes. Making the call in this
+ // handler ensures that the Actor has been successfully
+ // started
+ case "go" =>
+ server ! AsyncReq
+ }
+ }).start ! "go"
+ }
+ override def postStop = { server.stop }
+ }
+
+ scala> val future = SomeActor !!! GetSomethingForMe
+ scala> future.await
+ scala> future.result.get
+ res1: String = Here's some results
+!/sc!
+
+2.7 Actor Control *akka-actor-control* {{{2
+------------------------------------------------------------------------------
+
+{Actor}s can be started easily enough and, in fact /must/ be started before
+you can do anything with them. If you try to send a message to an {Actor}
+that has not been started then you're going to get yourself a big fat
+{akka.actor.ActorInitializationException}.
+
+2.7.1 Starting and Stopping *akka-actor-start-stop* {{{3
+------------------------------------------------------------------------------
+
+Both {Actor} and {ActorRef} have a {start} method on them.
+!sc!
+ scala> var a = actorOf(new Actor { def receive => } })
+ a: akka.actor.ActorRef =
+ Actor[$anonfun$1$$anon$1:3f434870-439f-11e0-8888-005056c00008]
+
+ scala> a.start
+
+ 20:00:49.721 [main] DEBUG
+ a.d.Dispatchers$globalExecutorBasedEventDrivenDispatcher$ -
+ Starting up
+ Dispatchers$globalExecutorBasedEventDrivenDispatcher$[
+ akka:event-driven:dispatcher:global]
+ with throughput [5]
+ res2: akka.actor.ActorRef =
+ Actor[$anonfun$1$$anon$1:3f434870-439f-11e0-8888-005056c00008]
+
+ scala> a.stop
+
+ 20:02:17.924 [main] INFO akka.actor.Scheduler$ - Starting up Scheduler
+ 20:02:18.935 [akka:scheduler-0]
+ DEBUG a.d.Dispatchers$globalExecutorBasedEventDrivenDispatcher$ -
+ Shutting down Dispatchers$globalExecutorBasedEventDrivenDispatcher$[
+ akka:event-driven:dispatcher:global]
+!/sc!
+
+Note: You can't start an {Actor} that's already been stopped.
+
+There's another way to shut down {Actor}s using the |akka-actor-registry|:
+!sc!
+ scala> a.start
+
+ scala> Actor.registry.shutdownAll
+ 20:05:04.055 [main] INFO akka.actor.ActorRegistry - Shutting down
+ all actors in the system...
+ 20:05:04.063 [main] DEBUG akka.util.ReflectiveAccess$ - Could not
+ get object [akka.actor.TypedActor$]
+ 20:05:04.119 [main] DEBUG akka.util.ReflectiveAccess$ - getObjectFor
+ java.lang.ClassNotFoundException: akka.actor.TypedActor$
+ at java.net.URLClassLoader$1.run(URLClassLoader.java:202) ~[na:1.6.0_22]
+ . . .
+ 20:05:04.157 [main] INFO akka.actor.ActorRegistry - All actors have been
+ shut down and unregistered from ActorRegistry
+
+ scala> a.isRunning
+ res7: Boolean = false
+!/sc!
+Note the exception. I'm not sure exactly why that's happened but I definitely
+don't have an {TypedActor}s running, so it may be trying to do some sort of
+Class Loader nonsense without checking for them first. The bottom line
+appears to be that the one {Actor} I had running is definitely stopped.
+
+
+2.7.2 Poison Pill *akka-actor-poisonpill* {{{3
+------------------------------------------------------------------------------
+
+Another way to kill an {Actor} off is to send it a {PoisonPill}:
+!sc!
+ scala> a.start
+ res9: akka.actor.ActorRef =
+ Actor[$anonfun$1$$anon$1:1330b630-43a1-11e0-8888-005056c00008]
+
+ scala> a ! PoisonPill
+ { ... shutdown messages here ... }
+!/sc!
+
+2.7.3 Actor Murder *akka-actor-murder* {{{3
+------------------------------------------------------------------------------
+
+This was meant to hold the {Kill} message, but it looks like it's an old API
+that's been removed in 1.0. {Kill} meant that the {Actor} should toss its
+cookies and the {Supervisor} should restart it, so "Kill" was a pretty silly
+name considering it didn't actually die.
+
+It looks like this has been replaced with {Restart} and {Exit} but I'm not
+sure why there are two of these... they both seem to do the same thing.
+
+ *Todo investigate this more by doing some experiments with the callbacks
+
+
+2.8 Hot-Swapping *akka-actor-hotswap* {{{2
+------------------------------------------------------------------------------
+
+Hot-swapping allows the application to swap in new {Actor} message loops at
+runtime. What you're doing is replacing the {PartialFunction[Any,Unit]}
+function that is normally created statically by defining the {receive}
+function. There are two ways you can do it:
+
+
+2.8.1 Invoking the Hot-Swap *akka-actor-invoke-hotswap* {{{3
+------------------------------------------------------------------------------
+
+- Send a "HotSwap" message to the {Actor}
+- Invoke the {become} method from within the {Actor}
+
+The hot-swapped code is kept on a {Stack} so that it can be pushed and popped.
+To hot-swap the {Actor} body using the "HotSwap" message:
+!sc!
+ actor ! HotSwap(self => {
+ case message => self.reply("hot-swapped body")
+ })
+!/sc!
+To hot-swap the {Actor} using {become}:
+!sc!
+ def angry: Receive = {
+ case "foo" => self reply "I am already angry!!!"
+ case "bar" => become(happy)
+ }
+
+ def happy: Receive = {
+ case "bar" => self reply "I am already happy :-)"
+ case "foo" => become(angry)
+ }
+
+ def receive = {
+ case "foo" => become(angry)
+ case "bar" => become(happy)
+ }
+!/sc!
+A decent use of hot-swapping is to implement a finite state machine. Here's
+an example of using hot-swapping:
+!sc!
+ case object Swap
+ class Swapper extends Actor {
+ def receive = {
+ case Swap =>
+ println("Hi")
+ become {
+ case Swap =>
+ println("Ho")
+ unbecome // resets the latest 'become' (just for fun)
+ }
+ }
+ }
+
+ val swap = actorOf[Swapper].start
+
+ swap ! Swap // prints Hi
+ swap ! Swap // prints Ho
+ swap ! Swap // prints Hi
+ swap ! Swap // prints Ho
+ swap ! Swap // prints Hi
+ swap ! Swap // prints Ho
+!/sc!
+
+2.8.2 Reverting the Hot-Swap *akka-actor-revert-hotswap* {{{3
+------------------------------------------------------------------------------
+
+Because the implementations are shoved on a {Stack}, you can also revert them.
+You do this by doing the opposite of what you did before:
+
+- Send a "RevertHotSwap" message to the {Actor}
+- Invoke the {unbecome} method from within the {Actor}
+
+To do it with the {RevertHotSwap} message:
+!sc!
+ actor ! RevertHotSwap
+!/sc!
+and to do it with the {unbecome} method:
+!sc!
+ def receive: Receive = {
+ case "revert" => unbecome
+ }
+!/sc!
+
+2.9 PartialFunction Chaining *akka-actor-partialfunc-chaining* {{{2
+------------------------------------------------------------------------------
+
+Here we can use the {orElse} method on {PartialFunction} to chain things
+together and allow for some extensibility:
+!sc!
+ abstract class GenericActor extends Actor {
+
+ // to be defined in subclassing actor
+ def specificMessageHandler: PartialFunction[Any, Unit]
+
+ // generic message handler
+ def genericMessageHandler = {
+ ... // generic message handler
+ }
+
+ def receive = specificMessageHandler orElse genericMessageHandler
+ }
+
+ class SpecificActor extends GenericActor {
+ def specificMessageHandler = {
+ ... // specific message handler
+ }
+ }
+!/sc!
+
+2.10 Actor Registry *akka-actor-registry* {{{2
+------------------------------------------------------------------------------
+
+Every time an {Actor} is started it is added to the {ActorRegistry} and every
+time it's stopped, it gets removed. The registered {Actor}s (by {ActorRef})
+are indexed by two identifiers: the {ActorRef}s {UUID} and the {ActorRef}s
+specific {Id}.
+
+An {ActorRef}'s {UUID} never changes, but its {Id} is can be modified by
+anyone at any time. The problem with that is that the mapping in the
+{ActorRegistry} has a copy of the {Id} in a key field so if it changes, you're
+going to be screwed.
+
+If you want to change the {Id}, you're going to have to {unregister} the
+{ActorRef} and then {register} it again.
+!sc!
+ scala> class MyActor extends Actor {
+ | def receive = {
+ | case "hi" =>
+ | }
+ | }
+ defined class MyActor
+
+ scala> def mkActor(id: String) = actorOf(new MyActor { self.id = id })
+ mkActor: (id: String)akka.actor.ActorRef
+
+ scala> var blues = mkActor("blue1") :: mkActor("blue2") ::
+ | mkActor("blue3") :: mkActor("blue4") :: Nil
+ blues: List[akka.actor.ActorRef] = List(
+ Actor[blue1:074eda70-43fd-11e0-a132-005056c00008],
+ Actor[blue2:07520ec0-43fd-11e0-a132-005056c00008],
+ Actor[blue3:07520ec1-43fd-11e0-a132-005056c00008],
+ Actor[blue4:07520ec2-43fd-11e0-a132-005056c00008])
+
+ scala> var reds = mkActor("red1") :: mkActor("red2") ::
+ mkActor("red3") :: mkActor("red4") :: Nil
+ reds: List[akka.actor.ActorRef] = List(
+ Actor[red1:15eb1670-43fd-11e0-a132-005056c00008],
+ Actor[red2:15eb1671-43fd-11e0-a132-005056c00008],
+ Actor[red3:15eb1672-43fd-11e0-a132-005056c00008],
+ Actor[red4:15eb1673-43fd-11e0-a132-005056c00008])
+
+ scala> blues.foreach(_.start)
+
+ scala> reds.foreach(_.start)
+
+ scala> Actor.registry.actors.foreach((x) => println(x.uuid + ": " + x.id))
+ 15eb1670-43fd-11e0-a132-005056c00008: red1
+ 07520ec2-43fd-11e0-a132-005056c00008: blue4
+ 15eb1673-43fd-11e0-a132-005056c00008: red4
+ 074eda70-43fd-11e0-a132-005056c00008: blue1
+ 15eb1671-43fd-11e0-a132-005056c00008: red2
+ 15eb1672-43fd-11e0-a132-005056c00008: red3
+ 07520ec0-43fd-11e0-a132-005056c00008: blue2
+ 07520ec1-43fd-11e0-a132-005056c00008: blue3
+
+ // I'm not really sure the 'find' function is of all that much use
+ scala> Actor.registry.find({
+ | case a: ActorRef if a.id endsWith "1" => a
+ | })
+ res6: Option[akka.actor.ActorRef] =
+ Some(Actor[red1:15eb1670-43fd-11e0-a132-005056c00008])
+
+ // When we can just do this instead:
+ scala> Actor.registry.actors.find((x) => x.id endsWith "1")
+ res7: Option[akka.actor.ActorRef] =
+ Some(Actor[red1:15eb1670-43fd-11e0-a132-005056c00008])
+!/sc!
+You can also register different types and pull them out based on their
+concrete type:
+!sc!
+ scala> actorOf(new NewActorType { self.id = "newType1" }).start
+ res9: akka.actor.ActorRef =
+ Actor[newType1:f6c57040-4403-11e0-a132-005056c00008]
+
+ scala> actorOf(new NewActorType { self.id = "newType2" }).start
+ res10: akka.actor.ActorRef =
+ Actor[newType2:f94934f0-4403-11e0-a132-005056c00008]
+
+ scala> actorOf(new NewActorType { self.id = "newType3" }).start
+ res11: akka.actor.ActorRef =
+ Actor[newType3:fb2c25c0-4403-11e0-a132-005056c00008]
+
+ scala> actorOf(new NewActorType { self.id = "newType4" }).start
+ res12: akka.actor.ActorRef =
+ Actor[newType4:fcdbd190-4403-11e0-a132-005056c00008]
+
+ scala> Actor.registry.actors.foreach((x) => println(x.uuid + ": " + x.id))
+ 15eb1670-43fd-11e0-a132-005056c00008: red1
+ 07520ec2-43fd-11e0-a132-005056c00008: blue4
+ fb2c25c0-4403-11e0-a132-005056c00008: newType3
+ 15eb1673-43fd-11e0-a132-005056c00008: red4
+ 074eda70-43fd-11e0-a132-005056c00008: blue1
+ 15eb1671-43fd-11e0-a132-005056c00008: red2
+ fcdbd190-4403-11e0-a132-005056c00008: newType4
+ f94934f0-4403-11e0-a132-005056c00008: newType2
+ f6c57040-4403-11e0-a132-005056c00008: newType1
+ 15eb1672-43fd-11e0-a132-005056c00008: red3
+ 07520ec0-43fd-11e0-a132-005056c00008: blue2
+ 07520ec1-43fd-11e0-a132-005056c00008: blue3
+
+ scala> Actor.registry.actorsFor[NewActorType]
+ res14: Array[akka.actor.ActorRef] = Array(
+ Actor[newType3:fb2c25c0-4403-11e0-a132-005056c00008],
+ Actor[newType4:fcdbd190-4403-11e0-a132-005056c00008],
+ Actor[newType2:f94934f0-4403-11e0-a132-005056c00008],
+ Actor[newType1:f6c57040-4403-11e0-a132-005056c00008])
+!/sc!
+And if you give a bunch of {Actor}s the same {Id} then you can pull them all
+out in a single {Array}:
+!sc!
+ scala> actorOf(new NewActorType { self.id = "sameId" }).start
+ res15: akka.actor.ActorRef =
+ Actor[sameId:6777d760-4404-11e0-a132-005056c00008]
+
+ scala> actorOf(new NewActorType { self.id = "sameId" }).start
+ res16: akka.actor.ActorRef =
+ Actor[sameId:67d75c80-4404-11e0-a132-005056c00008]
+
+ scala> actorOf(new NewActorType { self.id = "sameId" }).start
+ res17: akka.actor.ActorRef =
+ Actor[sameId:680b8be0-4404-11e0-a132-005056c00008]
+
+ scala> actorOf(new NewActorType { self.id = "sameId" }).start
+ res18: akka.actor.ActorRef =
+ Actor[sameId:6852ce10-4404-11e0-a132-005056c00008]
+
+ scala> Actor.registry.actorsFor("sameId")
+ res19: Array[akka.actor.ActorRef] = Array(
+ Actor[sameId:6777d760-4404-11e0-a132-005056c00008],
+ Actor[sameId:67d75c80-4404-11e0-a132-005056c00008],
+ Actor[sameId:680b8be0-4404-11e0-a132-005056c00008],
+ Actor[sameId:6852ce10-4404-11e0-a132-005056c00008])
+!/sc!
+
+2.11 Remote Actors *akka-actor-remote* {{{2
+------------------------------------------------------------------------------
+
+{Actor}s can be launched, connected-to, and managed remotely, and the work
+involved in doing all of this isn't much more complicated than doing the same
+locally.
+
+Remote {Actor}s are built on an efficient and scalable network I/O
+implementation based on JBoss Netty and Google Protocol Buffers.
+
+
+2.11.1 Starting Up Remote *akka-actor-remote-startup* {{{3
+------------------------------------------------------------------------------
+
+The {remote} subsystem is accessible via the |akka-actor-object|. It's pretty
+simple to start it up and shut it down:
+!sc!
+ scala> Actor.remote.start("localhost", 20000)
+ 08:50:30.730 [main] DEBUG akka.remote.netty.NettyRemoteSupport -
+ Starting up remote server on localhost:20000
+ res3: akka.remoteinterface.RemoteServerModule =
+ akka.remote.netty.NettyRemoteSupport@576f8789
+
+ scala> Actor.remote.shutdown
+ 08:51:13.821 [main] DEBUG akka.remote.netty.NettyRemoteSupport -
+ Shutting down remote server on localhost:20000
+!/sc!
+That's the programatic way to do it but you can also configure it via the
+configuration file ({akka.conf}):
+>
+ akka {
+ remote {
+
+ # generate your own with '$AKKA_HOME/scripts/generate_secure_cookie.sh'
+ # or using 'Crypt.generateSecureCookie'
+ secure-cookie = "050E0A0D0D06010A00000900040D060F0C09060B"
+
+ # Options: "zlib" (lzf to come), leave out for no compression
+ compression-scheme = "zlib"
+
+ # Options: 0-9 (1 being fastest and 9 being the most compressed), default
+ # is 6
+ zlib-compression-level = 6
+
+ server {
+ # The hostname or IP that clients should connect to
+ hostname = "localhost"
+
+ # The port clients should connect to. Default is 2552 (AKKA)
+ port = 2552
+
+ # Increase this if you want to be able to send messages with large
+ # payloads
+ message-frame-size = 1048576
+ connection-timeout = 1
+
+ # Should the remote server require that it peers share the same
+ # secure-cookie (defined in the 'remote' section)?
+ require-cookie = on
+
+ # Enable untrusted mode for full security of server managed actors,
+ # allows untrusted clients to connect.
+ untrusted-mode = off
+
+ # Sets the size of the connection backlog
+ backlog = 4096
+ }
+ }
+ }
+<
+Given the above configuration, then you can forego the programatic
+configuration and just let it default construct:
+!sc!
+ scala> Actor.remote.start
+ 08:57:02.175 [main] DEBUG akka.remote.netty.NettyRemoteSupport -
+ Starting up remote server on localhost:2552
+ res5: akka.remoteinterface.RemoteServerModule =
+ akka.remote.netty.NettyRemoteSupport@576f8789
+
+ scala> Actor.remote.shutdown
+ 08:57:07.460 [main] DEBUG akka.remote.netty.NettyRemoteSupport -
+ Shutting down remote server on localhost:2552
+!/sc!
+
+2.11.2 Registering Actors *akka-actor-remote-register* {{{3
+------------------------------------------------------------------------------
+
+If your code is taking the role of the "server" then it's reasonable to
+{register} your {Actor}s in the remote node directly after construction, like
+this:
+!sc!
+ scala> Actor.remote.start
+
+ scala> class Ponger extends Actor {
+ | def receive = {
+ | case "Ping" =>
+ | println("Received a Ping")
+ | self.reply("Pong")
+ | }
+ | }
+ defined class Ponger
+
+ scala> Actor.remote.register("pong-service", actorOf[Ponger])
+
+ scala> var ponger = Actor.remote.actorFor("pong-service", "localhost", 2552)
+
+ scala> ponger !! "Ping"
+ Received a Ping
+ res9: Option[Any] = Some(Pong)
+
+ scala> Actor.remote.shutdown
+!/sc!
+You can also register {Actor}s by their {UUID} instead of by their {Id} or
+{Handle} directly by prefixing the registration / deregistration with the
+{uuid} protocol:
+!sc!
+ remote.register("uuid:" + actor.uuid, actor)
+ remote.unregister("uuid:" + actor.uuid)
+!/sc!
+
+2.11.3 Invoking Actors Remotely *akka-actor-remote-invoke* {{{3
+------------------------------------------------------------------------------
+
+If you're the "client" then it might be reasonable to request that an {Actor}
+be launched on the remote node:
+!sc!
+ scala> var ponger = remote.actorOf[Ponger]("localhost", 2552).start
+ ponger: akka.actor.ActorRef =
+ Actor[Ponger:e89d51d0-440e-11e0-9725-005056c00008]
+
+ scala> ponger !! "Ping"
+ Received a Ping
+ res19: Option[Any] = Some(Pong)
+!/sc!
+You can also use the {spawnRemote} and {spawnLinkRemote} functions as well to
+launch {Actor}s remotely:
+!sc!
+ scala> val a = actorOf(new Actor {
+ | // spawnLinkRemote is another option, which has the same effect
+ | // for this particular use case, but obviously linking changes
+ | // in the more general sense.
+ | val ponger = self.spawnRemote[Ponger]("localhost", 2552, 600)
+ |
+ | def receive = {
+ | case "Ping" =>
+ | println("Calling the remote Ponger")
+ | self.reply(ponger !! "Ping")
+ | }
+ | }).start
+
+ scala> a !! "Ping"
+ Calling the remote Ponger
+ Received a Ping
+ res1: Option[Any] = Some(Some(Pong))
+!/sc!
+
+2.11.4 Connection Fault Tolerance *akka-actor-remote-resilience* {{{3
+------------------------------------------------------------------------------
+
+Remote clients automatically perform reconnection upon failure. You can
+configure it explicitly
+>
+ akka {
+ remote {
+ client {
+ reconnect-delay = 5
+ read-timeout = 10
+ message-frame-size = 1048576
+
+ # Maximum time window that a client should try to reconnect for
+ reconnection-time-window = 600
+ }
+ }
+ }
+<
+Eventually the reconnect attempt may timeout, at which point the next usage
+will yield a {RemoteClientException}. Now, I'm sure it's a pain in the ass to
+have to recognize this "at the right time", but assuming you go through that
+pain, the exception carries the reference to the {RemoteClient} so you could
+try to do an explicit connect if you want.
+
+It's probably easier to register a listener that will list for the
+{RemoteClientStopped} event instead of trying to deal with the exception
+"wherever it may occur".
+
+
+2.11.5 Remote Security *akka-actor-remote-security* {{{3
+------------------------------------------------------------------------------
+
+It's possible to run the server in "untrusted mode". Essentially, this stops
+the client from doing anything related to the {LifeCycle} of the {Actor}s
+running in the remote node. This includes:
+
+- Sending {LifeCycle} control messages
+ - HotSwap
+ - RevertHotSwap
+ - Restart
+ - Exit
+ - Link
+ - Unlink
+ - UnlinkAndStop
+ - ReceiveTimeout
+- Invoking {LifeCycle} affecting commands
+ - start
+ - stop
+ - link
+ - unlink
+ - spawnLink
+ - etc...
+
+You turn on "untrusted mode" with a configuration parameter:
+>
+ akka {
+ remote {
+ server {
+ # Enable untrusted mode for full security of server managed actors,
+ # allows untrusted clients to connect.
+ untrusted-mode = on
+ }
+ }
+ }
+<
+Akka also has a "secure cookie" mechanism similar to that used in {Erlang}.
+Assuming all your nodes are configured appropriately to use the secure cookie,
+and you have configured the node to require the cookie:
+>
+ akka {
+ remote {
+ # generate your own with '$AKKA_HOME/scripts/generate_secure_cookie.sh'
+ # or using 'Crypt.generateSecureCookie'
+ secure-cookie = "050E0A0D0D06010A00000900040D060F0C09060B"
+
+ server {
+ # Should the remote server require that it peers share the same
+ # secure-cookie (defined in the 'remote' section)?
+ require-cookie = on
+ }
+ }
+ }
+<
+When connecting, a client will send its cookie across SSL and, assuming it
+matches the server's version, the client will be granted full access and, if
+not you will get a {java.lang.SecurityException}.
+
+2.11.6 Session Based Servers *akka-actor-remote-sessions* {{{3
+------------------------------------------------------------------------------
+
+You can specify that Server-side {Actor}s be created on a "session" basis,
+such that every new client {Actor} that connects would get a new {Actor}
+instance for that particular registration. The {Actor}s are stopped
+automatically when the client disconnects.
+
+A session-based {Actor} would be useful if we need to keep some per-session
+state such as a username or want to do a per-client amount of cleanup by
+overriding the {postStop} method on the server-side {Actor}.
+
+Getting a session-based {Actor} up and running is dead simple - just use
+{registerPerSession} instead of {register}:
+!sc!
+ class Ponger extends Actor {
+ def receive = {
+ case "Ping" => self.reply("Pong")
+ }
+ }
+
+ remote.start
+ remote.registerPerSession("pong-service", actorOf[Ponger])
+!/sc!
+According to the ScalaDoc for the {registerPerSession} method, we must
+{unregister} the actor by this {Id} on our own.
+
+
+2.11.7 Event Listening *akka-actor-remote-events* {{{3
+------------------------------------------------------------------------------
+
+The remote node will publish client-related events to registered listeners:
+!sc!
+ val listener = actorOf(new Actor {
+ def receive = {
+ case RemoteClientError(cause, client, address) => ...
+ case RemoteClientDisconnected(client, address) => ...
+ case RemoteClientConnected(client, address) => ...
+ case RemoteClientStarted(client, address) => ...
+ case RemoteClientShutdown(client, address) => ...
+ case RemoteClientWriteFailed(request, cause, client, address) => ...
+ case _ => //ignore other
+ }
+ }).start
+ remote.addListener(listener)
+ ...
+ remote.removeListener(listener)
+!/sc!
+And the same types of events are availble for server-related objects:
+!sc!
+ val listener = actorOf(new Actor {
+ def receive = {
+ case RemoteServerStarted(server) => ...
+ case RemoteServerShutdown(server) => ...
+ case RemoteServerError(cause, server) => ...
+ case RemoteServerClientConnected(server, clientAddress) => ...
+ case RemoteServerClientDisconnected(server, clientAddress) => ...
+ case RemoteServerClientClosed(server, clientAddress) => ...
+ case RemoteServerWriteFailed(request, casue, server, clientAddress) => ...
+ case _ => //ignore other
+ }
+ }).start
+ remote.addListener(listener)
+ ...
+ remote.removeListener(listener)
+!/sc!
+
+2.11.8 Messge Serialization *akka-actor-remote-serialization* {{{3
+------------------------------------------------------------------------------
+
+ *Todo needs to be investigated
+
+
+==============================================================================
+2.12 Scheduler *akka-actor-scheduler* {{{2
+------------------------------------------------------------------------------
+
+The {akka.actor.Scheduler} object has a few neat methods on it that provide
+some really great "timer" functions. I used this recently to push test data
+through the system at random intervals.
+!sc!
+ import akka.actor.{Scheduler, Actor}
+ import java.util.concurrent.TimeUnit
+
+ case class PostNewMessage(msg: String)
+ case class PushTo(to: ActorRef, msgs: List[String])
+
+ class Pusher extends Actor {
+ val r = new Random
+ def receive = {
+ case PushTo(to, msgs) =>
+ if (!msgs.isEmpty) {
+ // The goal function - post the message
+ to ! PostNewMessage(msgs.head)
+ // But not too quickly. Send the rest of the messages to ourself
+ // within the next 30 seconds so that we can call
+ // "to ! PostNewMessage" again.
+ Scheduler.scheduleOnce(() => self ! PushTo(to, msgs.tail),
+ r.nextInt(30), TimeUnit.SECONDS)
+ } else {
+ self.stop
+ }
+ }
+ }
+!/sc!
+
+2.13 Mailboxes *akka-actor-mailboxes* {{{2
+------------------------------------------------------------------------------
+
+ *Todo this is a placeholder
+
+ What I really want to know at this point is how to create a priority
+ mailbox. The current use-case is that I want to be able to put in a
+ "DrainYourself" message, but I want it to be pulled out of the mailbox
+ only if there are no other messages in there.
+
+2.13.1 Viktor's Priority Mailbox *akka-priority-mailbox* {{{3
+------------------------------------------------------------------------------
+
+Viktor Klang threw this together, an I've pulled it from the original post at
+https://groups.google.com/group/akka-user/browse_thread/thread/67077cad1b2bc4b2.
+It may completely suck, but I've put it here for instructional purposes:
+!sc!
+class UnboundedPriorityMessageQueue(
+ blockDequeue: Boolean,
+ cmp: Comparator[MessageInvocation]) extends
+ PriorityBlockingQueue[MessageInvocation](11, cmp) with MessageQueue {
+
+ final def enqueue(handle: MessageInvocation) {
+ this add handle
+ }
+
+ final def dequeue(): MessageInvocation = {
+ if (blockDequeue) this.take()
+ else this.poll()
+ }
+}
+
+class BoundedPriorityMessageQueue(
+ capacity: Int,
+ pushTimeOut: Duration,
+ blockDequeue: Boolean,
+ cmp: Comparator[MessageInvocation]) extends
+ PriorityBlockingQueue[MessageInvocation](capacity, cmp) with
+ MessageQueue {
+
+ final def enqueue(handle: MessageInvocation) {
+ if (pushTimeOut.toMillis > 0) {
+ if (!this.offer(handle, pushTimeOut.length, pushTimeOut.unit))
+ throw new MessageQueueAppendFailedException(
+ "Couldn't enqueue message " + handle + " to " + toString)
+ } else {
+ this.put(handle)
+ }
+ }
+
+ final def dequeue(): MessageInvocation =
+ if (blockDequeue) this.take()
+ else this.poll()
+}
+
+class PriorityExecutorBasedEventDrivenDispatcher(
+ name: String,
+ comparator: Comparator[MessageInvocation],
+ throughput: Int = Dispatchers.THROUGHPUT,
+ throughputDeadlineTime: Int = Dispatchers.THROUGHPUT_DEADLINE_TIME_MILLIS,
+ mailboxType: MailboxType = Dispatchers.MAILBOX_TYPE,
+ config: ThreadPoolConfig = ThreadPoolConfig()
+ ) extends ExecutorBasedEventDrivenDispatcher(
+ name,
+ throughput,
+ throughputDeadlineTime, mailboxType, config) {
+
+ override def createMailbox(actorRef: ActorRef): AnyRef =
+ mailboxType match {
+ case UnboundedMailbox(blocking) =>
+ new UnboundedPriorityMessageQueue(blocking, comparator) with ExecutableMailbox {
+ def dispatcher = PriorityExecutorBasedEventDrivenDispatcher.this
+ }
+
+ case BoundedMailbox(blocking, capacity, pushTimeOut) =>
+ new BoundedPriorityMessageQueue(capacity, pushTimeOut, blocking, comparator) with ExecutableMailbox {
+ def dispatcher = PriorityExecutorBasedEventDrivenDispatcher.this
+ }
+ }
+}
+
+
+scala> object PriorityMessageDispatcher {
+ | val comparator = new Comparator[MessageInvocation] ...
+ | val instance = new PriorityExecutorBasedEventDrivenDispatcher("PriorityMessageDispatcher",comparator)
+ | }
+
+scala> val a = actorOf(...)
+scala> a.dispatcher = PriorityMessageDispatcher.instance
+scala> a.start
+!/sc!
+
+==============================================================================
+3. Actor Supervision *akka-supervision* {{{1
+------------------------------------------------------------------------------
+
+The core of the Akka supervision subsystem is shamelessly ripped off from
+Erlang's Open Telecom Platform (http://trapexit.org). The OTP is a system
+that brings concurrency and failure together into a single unified platform
+where the key point is that failure is designed in to the system. The
+brilliance is that we no long ignore failure and then try to design it out of
+the systems we build - which never works, of course. Instead, we expect
+failure and handle it appropriately. It's this philosophy, coupled with live
+upgrades that takes a system from 3 9's uptime, or even 5 9's uptime to 9 9's
+uptime.
+
+
+3.1 So Why Not Just Use Erlang/OTP? *akka-why-not-erlang* {{{2
+------------------------------------------------------------------------------
+
+It's simple pragmatism: Akka is built for the JVM and, as such, has access to
+the entire Java community. This means developers (many more Java developers
+than Erlang developers) and toolkits / frameworks.
+
+It's really that simple.
+
+
+3.2 Designing for Failure *akka-design-for-failure* {{{2
+------------------------------------------------------------------------------
+
+Fortunately, because Akka takes a page out of Erlang's playbook here, we can
+use all of Erlang's already proven design principles.
+
+The idea is to layer your system design like an onion; keep the most critical
+state in the centre and build out less reliable services on top of it. The
+only thing that's really critical is 'state' that cannot be reconstructed, and
+an {Actor} that is responsible for managing this state is clearly destined for
+the iron-clad centre of the design.
+
+Anything that operates on that data, and could therefore throw exceptions
+(e.g. a simple Parsing exception) should be delegated to an {Actor} that can
+fail gracefully and be restarted by a {Supervisor}.
+
+
+3.3 Setting Up Supervision *akka-setting-up-supervision* {{{2
+------------------------------------------------------------------------------
+
+There are a number of ways to do this, so it can be a bit confusing. First we
+need to cover some terminology and package details.
+
+Any {Actor} can supervise any other {Actor}, so without going into the details
+just yet, we observe that an {Actor} does not supervise itself. An {Actor} is
+supervised by another {Actor} through a process of "linking". An {Actor}
+which has another {Actor} linked to it takes on the role of the {Supervisor}.
+The {Actor} which has been linked to is being supervised and will be managed
+by the {Supervisor}.
+
+This can occur in as deep of a hierarchy as you like, and can occur across
+nodes in a cluster as well.
+
+
+3.3.1 Fault Handling Strategies *akka-fault-handling-strategies* {{{3
+------------------------------------------------------------------------------
+
+There are currently two fault handling strategies in Akka:
+!sc!
+ import akka.config.Supervision.AllForOneStrategy
+ import akka.config.Supervision.OneForOneStrategy
+!/sc!
+To understand this we need to remember that a single {Supervisor} may be
+supervising a number of {Actor}s simultaneously. These two strategies discuss
+what should happen when any of the supervised {Actors} has a failure. The
+{AllForOneStrategy} states that a single failed {Actor} requires the restart
+of all {Actors} being supervised by the {Supervisor}. The {OneForOneStrategy}
+states that only the failed {Actor} will be restarted.
+
+
+3.3.2 Restart LifeCycles *akka-restart-lifecycles* {{{3
+------------------------------------------------------------------------------
+
+An {Actor} may or may not be restarted by a {Supervisor} depending on how it
+its {LifeCycle} is defined:
+!sc!
+ import akka.config.Supervision.Permanent
+ import akka.config.Supervision.Temporary
+!/sc!
+A {Permanent} {LifeCycle} indicates that the {Actor} must be restarted every
+time it fails while a {Temporary} {LifeCycle} indicates that a failed {Actor}
+must be properly {stopped} after the failure. This ensures orderly shutdown
+of a failed {Actor}.
+
+
+3.3.3 Declarative Setup *akka-supervision-declarative-setup* {{{3
+------------------------------------------------------------------------------
+
+The documentation at http://bit.ly/eNTJSm states the following:
+!sc!
+ val supervisor = Supervisor(
+ SupervisorConfig(
+ AllForOneStrategy(List(classOf[Exception]), 3, 1000),
+ Supervise(
+ actorOf[MyActor1],
+ Permanent) ::
+ Supervise(
+ actorOf[MyActor2],
+ Permanent) ::
+ Nil))
+!/sc!
+However, this doesn't seem to work - perhaps something changed in 1.1 (as
+that's what I'm currently using). What does work is the following:
+!sc!
+ val supervisor = Supervisor(
+ SupervisorConfig(
+ AllForOneStrategy(List(classOf[Exception]), 3, 1000),
+ Supervise(
+ actorOf(new MyActor1),
+ Permanent) ::
+ Supervise(
+ actorOf(new MyActor2),
+ Permanent) ::
+ Nil))
+!/sc!
+Note that the only way you're going to get access to the {Actor}s after this
+is through the |akka-actor-registry| so that approach may not be the most
+pragmatic, depending on how you identify your {Actor}s.
+
+You can easily do this, of course:
+!sc!
+ val actor1 = actorOf[MyActor1]
+ val actor2 = actorOf[MyActor2]
+ val supervisor = Supervisor(
+ SupervisorConfig(
+ AllForOneStrategy(List(classOf[Exception]), 3, 1000),
+ Supervise(actor1, Permanent) ::
+ Supervise(actor2, Permanent) ::
+ Nil))
+!/sc!
+
+3.3.3.1 Declarative Example *akka-supervision-declarative-example* {{{4
+------------------------------------------------------------------------------
+!sc!
+ import akka.config.Supervision._
+ import akka.actor.Actor._
+ import akka.actor._
+
+ class MyActor extends Actor {
+ def receive = {
+ case "throw" => throw new RuntimeException("Die, bastard!")
+ case msg => println(msg)
+ }
+
+ override def postRestart(reason: scala.Throwable) {
+ println(self.id + ": restarting with reason - " + reason.getMessage)
+ }
+
+ override def postStop {
+ println(self.id + ": stopping normally")
+ }
+ }
+
+ var supervisor = Supervisor(SupervisorConfig(
+ AllForOneStrategy(List(classOf[Exception]), 3, 1000),
+ Supervise(actorOf(new MyActor {
+ self.id = "MyActor1 Permanent"
+ }), Permanent) ::
+ Supervise(actorOf(new MyActor {
+ self.id = "MyActor2 Permanent"
+ }), Permanent) ::
+ Supervise(actorOf(new MyActor {
+ self.id = "MyActor3 Temporary"
+ }), Permanent) ::
+ Supervise(actorOf(new MyActor {
+ self.id = "MyActor4 Permanent"
+ }), Permanent) ::
+ Supervise(actorOf(new MyActor {
+ self.id = "MyActor5 Permanent"
+ }), Permanent) ::
+ Nil))
+
+ registry.actors.head ! "throw"
+ Thread.sleep(200)
+ registry.actors.foreach(_ ! "booger")
+ Thread.sleep(2000)
+ registry.shutdownAll
+!/sc!
+The above outputs the following:
+>
+ MyActor3 Temporary: stopping normally
+ MyActor4 Permanent: restarting with reason - Die, bastard!
+ MyActor2 Permanent: restarting with reason - Die, bastard!
+ MyActor1 Permanent: restarting with reason - Die, bastard!
+ MyActor5 Permanent: restarting with reason - Die, bastard!
+ booger
+ booger
+ booger
+ booger
+ MyActor4 Permanent: stopping normally
+ MyActor2 Permanent: stopping normally
+ MyActor1 Permanent: stopping normally
+ MyActor5 Permanent: stopping normally
+<
+
+3.3.4 Programmatic Setup *akka-supervision-programmatic-setup* {{{3
+------------------------------------------------------------------------------
+
+Things can be done more programmatically and thus more flexibly with the
+following:
+!sc!
+ class MySupervisor extends Actor {
+ self.faultHandler = OneForOneStrategy(List(classOf[Throwable]), 5, 5000)
+
+ def receive = {
+ case Register(actor) =>
+ self.link(actor)
+ }
+ }
+!/sc!
+See the programmatic setup of the {FaultHandlingStrategy} by setting
+{self.faultHandler} and the dynamic linking of {Actor}s using the {self.link}
+call.
+
+3.3.5 Getting Your Supervisor *akka-supervision-getting-supervisor* {{{3
+------------------------------------------------------------------------------
+
+It can be useful to be able to talk to your {Supervisor}, as in the following
+example:
+!sc!
+ case PleaseDie =>
+ supervisor.foreach(_ ! Unlink(this))
+!/sc!
+
+3.3.6 Chained Restarts *akka-supervision-chained-restarts* {{{3
+------------------------------------------------------------------------------
+
+ *Error i have a bug filed against Akka for this
+
+There is undefined behaviour here. I have filed ticket "707: Chained
+supervisors fail to restart Actors properly" (http://bit.ly/fiAB7u).
+
+My assumption was that, if you have a chain, defined like this:
+!sc!
+ import akka.actor.Actor._
+ import akka.actor._
+ import akka.config.Supervision._
+
+ case object Die
+
+ class Chainer(myId: String, a: Option[ActorRef] = None) extends Actor {
+ self.id = myId
+ self.lifeCycle = Permanent
+ self.faultHandler = OneForOneStrategy(List(classOf[Exception]), 3, 1000)
+ a.foreach(self.link(_))
+ a.foreach((a) => println(self.id + " starting up with a = " + a.id))
+
+ def receive = {
+ case Die => throw new Exception(self.id + ": Blurgh!")
+ }
+
+ override def preRestart(reason: scala.Throwable) {
+ println(reason.getMessage + ": " + self.mailboxSize)
+ }
+ }
+
+ val lastActor = actorOf(new Chainer("lastActor")).start
+ val middleActor = actorOf(new Chainer("middleActor", Some(lastActor))).start
+ val headActor = actorOf(new Chainer("headActor", Some(middleActor))).start
+ val supervisor = Supervisor(
+ SupervisorConfig(
+ OneForOneStrategy(List(classOf[Exception]), 3, 1000),
+ Supervise(headActor, Permanent) :: Nil
+ )).start
+
+ lastActor ! Die
+ Thread.sleep(100)
+ middleActor ! Die
+ Thread.sleep(100)
+ supervisor.shutdown
+!/sc!
+Then the death of {lastActor} would have it restarted, as would {middleActor}
+or {headActor}; I wouldn't expect others to get restarted at all. What's
+happening isn't either of those things:
+>
+ middleActor starting up with a = lastActor
+ headActor starting up with a = middleActor
+ lastActor: Blurgh!: 0
+ middleActor: Blurgh!: 0
+ middleActor: Blurgh!: 0
+ middleActor: Blurgh!: 0
+<
+
+3.4 Non-Blocking Failure *akka-non-blocking-failure* {{{2
+------------------------------------------------------------------------------
+
+Akka 1.1 has introduced a very important feature that allows for greater use
+of non-blocking calls that are resilient in the face of failure.
+
+The typical problem is this:
+!sc!
+ class ServerActor extends Actor {
+ def receive = {
+ case Ping =>
+ if (currentTime % 10000 == 0)
+ throw RuntimeException("Die, you devil!")
+ self.sender.foreach(_ ! Pong)
+ }
+ }
+
+ class ClientActor(server: ActorRef) extends Actor {
+ def receive = {
+ case Ping =>
+ server ! Ping
+ case Pong =>
+ print("I'm so happy")
+ }
+ }
+!/sc!
+Here we see that, should the current time happen to be divisible by 10000
+milliseconds when a {Ping} message comes in, the {ServerActor} is going to
+throw a {RuntimeException}. Now, even if a {Supervisor} is watching it and
+restarts it, the {Ping} message is going to be lost. And, because we have a
+non-blocking Request / Response paradigm going on here, the {ClientActor} is
+going to be left in the dark.
+
+A possible answer to this problem is to spool up a slave {Actor} to be
+dedicated to receive the response and forward that back to the originator,
+retrying the initial send on a timeout:
+!sc!
+ class ClientActor extends Actor {
+ def receive = {
+ case Ping =>
+ val originator = self
+ self.startLink(actorOf(new Actor {
+ self.receiveTimeout = Some(5000L)
+ def recieve = {
+ case PingTo(server) =>
+ server ! Ping
+ case pong @ Pong =>
+ originator forward pong
+ supervisor.foreach(_ ! Unlink(this))
+ case ReceiveTimeout =>
+ server ! Ping
+ }
+ })
+ case Pong =>
+ print("I'm so happy")
+ }
+ }
+!/sc!
+This is, of course, not ideal because it assumes that the {ServerActor} has
+croaked. If it hasn't, and is merely slow, then the {ServerActor} now has two
+{Ping} messages waiting to be processed, which causes two problems:
+
+ 1) The {ClientActor}'s slave is going to get two {Pong}s. In the case of
+ a {Pong} it's not such a big deal, but with a more substantial message,
+ it could be an issue.
+ 2) The (already slow) {ServerActor} has even more work to do.
+
+Akka 1.0 has a way to deal with this, but it assumes a blocking call:
+!sc!
+ // or postRestart
+ override def preRestart(reason: scala.Throwable) {
+ // reply_? is a "safe" reply that doesn't fail if there's nothing
+ // to reply to
+ self.reply_?(reason.getMessage)
+ }
+!/sc!
+However a {reply} by definition requires a {Future} to reply to, and that
+assumes some fashion of blocking call is taking place, which is something
+we're trying to avoid. Fortunately, Akka 1.1 (still in SNAPSHOT phase)
+provides access to the original {sender} as well, which makes the following
+possible:
+!sc!
+ class ServerActor extends Actor {
+ def recieve = {
+ case Ping =>
+ if (currentTime % 10000 == 0) throw PingException("Die, you devil!")
+ self.sender.foreach(_ ! Pong)
+ }
+
+ override def preRestart(reason: scala.Throwable) {
+ reason match {
+ case PingException(message) =>
+ self.sender.foreach(_ ! PingServerActorRestarted(message))
+ case _ =>
+ }
+ }
+ }
+!/sc!
+Now, we can create the {ClientActor} (or a trait that it mixes in) capable of
+receiving the {PingServerActorRestarted} message and react accordingly. One
+could easily envision a trait that retries the failed operation since the
+{ClientActor} is (arguably) the entity in the best position to understand the
+context of its request enough to initiate the retry.
+
+
+==============================================================================
+4. Actor Routing *akka-routing* {{{1
+------------------------------------------------------------------------------
+
+Routing is tightly coupled with |akka-actors| but are technically in their own
+distinct realm so they can be studied separately.
+
+The Routing framework gives us a mechanism by which we can route work to
+{Actor}s in different ways in order to help us load balance them and/or
+provide another level of fault tolerance by sending the same message to
+multiple {Actor}s in order to increase the liklihood of a response message in
+the face of "interesting" failures.
+
+
+4.1 Simple Dispatching *akka-routing-dispatching* {{{2
+------------------------------------------------------------------------------
+
+There are a couple of ways to get a dispatcher up and running. The first way
+is to use the factory method located in the {akka.routing.Routing} companion
+object:
+!sc!
+ import akka.actor.Actor._
+ import akka.actor.Actor
+ import akka.routing.Routing._
+
+ case object Ping
+ case object Pong
+
+ val pinger = actorOf(new Actor {
+ def receive = { case msg => println("Pinger: " + msg) }
+ }).start
+
+ val ponger = actorOf(new Actor {
+ def receive = { case msg => println("Ponger: " + msg) }
+ }).start
+
+ val d = dispatcherActor {
+ case Ping => pinger
+ case Pong => ponger
+ }
+
+ scala> d ! Ping
+ Pinger: Ping
+
+ scala> d ! Pong
+ Ponger: Pong
+!/sc!
+As can be seen, the messages only get routed if they go through the
+{dispatcher}, obviously. I suppose if we wanted, we could send to the
+{dispatcher} and also send to the {Actor}s directly however we saw fit.
+
+Another way to do the same thing, but provides more programmatic flexibility
+is to mix in the {Dispatcher} trait and define the {routes} method:
+!sc!
+ import akka.actor.Actor
+ import akka.actor.Actor._
+ import akka.routing.Dispatcher
+
+ case object Ping
+ case object Pong
+
+ class MyDispatcher extends Actor with Dispatcher {
+ val pinger = actorOf(new Actor {
+ def receive = { case msg => println("Pinger: " + msg) }
+ }).start
+ val ponger = actorOf(new Actor {
+ def receive = { case msg => println("Ponger: " + msg) }
+ }).start
+ def routes = {
+ case Ping => pinger
+ case Pong => ponger
+ }
+ }
+
+ val d = actorOf[MyDispatcher].start
+
+ scala> d ! Ping
+ Pinger: Ping
+
+ scala> d ! Pong
+ Ponger: Pong
+!/sc!
+
+4.2 Simple Load Balancing *akka-routing-loadbalance* {{{2
+------------------------------------------------------------------------------
+
+Another way to route information is using a {LoadBalancer}. Again, there are
+a couple of ways to do this, with the first being more ad-hoc than the second:
+!sc!
+ import akka.actor.Actor._
+ import akka.actor.Actor
+ import akka.routing.Routing._
+ import akka.routing.CyclicIterator
+
+ case object Ping
+ case object Pong
+
+ val pinger = actorOf(new Actor {
+ def receive = { case msg => println("Pinger: " + msg) }
+ }).start
+ val ponger = actorOf(new Actor {
+ def receive = { case msg => println("Ponger: " + msg) }
+ }).start
+
+ val d = loadBalancerActor(new CyclicIterator(List(pinger, ponger)))
+
+ scala> d ! Ping
+ Pinger: Ping
+
+ scala> d ! Ping
+ Ponger: Ping
+
+ scala> d ! Pong
+ Pinger: Pong
+
+ scala> d ! Pong
+ Ponger: Pong
+!/sc!
+Above we can see a simple "round robin" load balancer such that we keep moving
+around the {List} routing to the next candidate regardless of what's happening
+in the system.
+!sc!
+ import akka.actor._
+ import akka.actor.Actor._
+ import akka.routing.{LoadBalancer, CyclicIterator}
+
+ case object Ping
+ case object Pong
+
+ class MyLoadBalancer extends Actor with LoadBalancer {
+ val pinger = actorOf(new Actor {
+ def receive = { case msg => println("Pinger: " + msg) }
+ }).start
+ val ponger = actorOf(new Actor {
+ def receive = { case msg => println("Ponger: " + msg) }
+ }).start
+
+ val seq = new CyclicIterator[ActorRef](List(pinger, ponger))
+ }
+
+ val d = actorOf[MyLoadBalancer].start
+
+ scala> d ! Ping
+ Pinger: Ping
+
+ scala> d ! Ping
+ Ponger: Ping
+
+ scala> d ! Pong
+ Pinger: Pong
+
+ scala> d ! Pong
+ Ponger: Pong
+!/sc!
+Beyond the {CyclicIterator}, we can use a more intelligent iterator that
+routes based on the size of the {Mailbox} in the {ActorRef}. Creating one of
+these is as simple as the above:
+!sc!
+ import akka.routing.SmallestMailboxFirstIterator
+
+ val d = loadBalancerActor(new SmallestMailboxFirstIterator(
+ List(pinger, ponger)))
+!/sc!
+
+4.3 Actor Pools *akka-routing-pools* {{{2
+------------------------------------------------------------------------------
+
+{Actor} Pools are more complex than the simple mechanisms described above, but
+in truth, they're probably the only serious method you'd ever use in a real
+application.
+
+A Pool provides the ability to dynamically shrink and grow the number of
+available {Actor}s based on {capacity} and {pressure}, as well as providing a
+number of different parameters to enhance the routing strategy.
+
+ *Error it turns out these aren't in 1.0 yet. I can see them in the git
+ *Error repository but they're not in the distribution yet. I'm going to
+ *Error hold off on these for the moment.
+
+
+==============================================================================
+5. Cloudy Akka *akka-cloudy-akka* {{{1
+------------------------------------------------------------------------------
+
+Akka also provides a "cloud" product called "Cloudy Akka". I don't know too
+much about it at this point but the information can be found here:
+http://scalablesolutions.se/products.html.
+
+Essentially it supports clustering and management of the cluster with the
+standard Akka features of remote execution and the like.
+
+
+Modelines: {{{1
+vim:tw=78:ts=4:ft=help:fdm=marker:fdl=0
View
4,509 bundle/syntax_scala/doc/scala_info.txt
4,509 additions, 0 deletions not shown
View
373 bundle/syntax_scala/doc/scala_quick_ref.txt
@@ -0,0 +1,373 @@
+*scala-quick-ref.txt* Scala Quick Reference Mar 26, 2011
+
+Author: Derek Wyatt <derek@{my first name}{my last name}.org>
+
+Copyright: (c) 2011 by Derek Wyatt
+ No license implied... use it for whatever tickles your particular
+ fancy.
+
+==============================================================================
+0. Contents *scala-quick-ref*
+------------------------------------------------------------------------------
+
+
+
+==============================================================================
+1. Symbolics *scala-qr-symbolics* {{{1
+------------------------------------------------------------------------------
+
+-> *scala-qr-pairmap*
+ Returns a two-element tuple containing the key and value
+!sc!
+ Map(1 -> "A", 2 -> "B")
+ (1).->("A")
+!/sc!
+_ *scala-qr-placeholder*
+ A placeholder used in imports, function literals, etc...
+!sc!
+ import com.xtech._
+ case _ => valute.toString
+ numbers.filter(_ < 0)
+!/sc!
+: *scala-qr-colon*
+ Separators between identifiers and type annotations
+!sc!
+ def add(i: Int): Int = ...
+!/sc!
+= *scala-qr-assignment* *scala-qr-=*
+ Assignment
+!sc!
+ val one = "1"
+!/sc!
+=> *scala-qr-equalarrow*
+ Used in function literals to separate the argument list from the function
+ body. Also used to separate case conditions from the case body
+!sc!
+ numbers.filter(x => x < 10)
+ case Condition => body
+ def func((A, B) => ReturnValue) = ...
+!/sc!
+<- *scala-qr-forarrow*
+ Used in for comprehensions in generator expressions
+!sc!
+ for (arg <- args)
+!/sc!
+<: *scala-qr-upper-bounds*
+ Upper bounds (a subtype of). Used in parameterized and abstract type
+ declarations to constrain the allowed types
+!sc!
+ def apply[T <:U](x: T) = ...
+!/sc!
+>: *scala-qr-lower-bounds*
+ Lower bounds (supertype of). Used in parameterized and abstract type
+ declarations to constrain the allowed types
+!sc!
+ def append[U >: T](x: U) = ...
+!/sc!
+<% *scala-qr-view-bounds*
+ View bounds (apply implicit conversion). Used in parameterized and
+ abstract type declarations to convert the type using view.
+!sc!
+ def m[A <% B](args): R = ...
+!/sc!
+# *scala-qr-contained-type*
+ Allows you to refer to a type declaration nested in another type
+!sc!
+ val ic: MyClass#myType = ...
+!/sc!
+@ *scala-qr-annotation*
+ Marks an annotation.
+!sc!
+ @deprecated def bad() = ...
+!/sc!
+' *scala-qr-quote* *scala-qr-symbol*
+ Lets you declare / reference a symbol.
+!sc!
+ val s = 'aSymbol
+ def doit(r: Symbol) {
+ println(s.name)
+ }
+!/sc!
+(infix) *scala-qr-infix-notation*
+ Allows you to use any method invocation in an infix notation style.
+!sc!
+ 1 + 2 // as opposed to...
+ 1.+(2)
+!/sc!
+
+==============================================================================
+2. Variables *scala-qr-variables* {{{1
+------------------------------------------------------------------------------
+
+Immutable (final) *scala-qr-immutable-values*
+ The de-facto standard mechanism for declaring memory storage locations in
+ Scala.
+!sc!
+ val msg = "Hello, World!"
+ val msg: String = "Hello, World!"
+ val big = new java.math.BigInteger("12345")
+!/sc!
+Mutable *scala-qr-mutable-variables*
+ Creates mutable locations that can be reassigned at any time.
+!sc!
+ var greets = "Hello, World!"
+ var greets: String = "Hello, World!"
+!/sc!
+Lazy initialization *scala-qr-lazy*
+ Allows the value to be initialized on first use.
+!sc!
+ object Demo {
+ lazy val x = { println("initializing x"); "done" }
+ }
+!/sc!
+
+==============================================================================
+3. Basic Types *scala-qr-basic-types* {{{1
+------------------------------------------------------------------------------
+
+Byte *scala-qr-byte*
+ 8-bit signed two's complement integer
+ (-2)^7 to (2)^7 - 1, inclusive
+
+Short *scala-qr-short*
+ 16-bit signed two's complement integer
+ (-2)^15 to (2)^15 - 1, inclusive
+
+Int *scala-qr-int*
+ 32-bit signed two's complement integer
+ (-2)^31 to (2)^31 - 1, inclusive
+
+Long *scala-qr-long*
+ 64-bit signed two's complement integer
+ (-2)^63 to (2)^63 - 1, inclusive
+
+Char *scala-qr-char*
+ 16-bit unsigned Unicode character
+ 0 to (2)^16 - 1, inclusive
+
+String *scala-qr-string*
+ A sequence of Chars
+
+Float *scala-qr-float*
+ 32-bit IEEE 754 single-precision float
+
+Double *scala-qr-double*
+ 64-bit IEEE 754 double-precision float
+
+Boolean *scala-qr-boolean*
+ ture or false
+
+
+==============================================================================
+4. Operators *scala-qr-operators* {{{1
+------------------------------------------------------------------------------
+
+Technically speaking, Scala has no operators; it only has methods and
+functions. Scala allows a lot of interesting characters to be used to define
+methods and functions, so they can look like operators.
+
++,-,*,/,% *scala-qr-arithmetics*
+ Arithmetic operations
+!sc!
+ val x = 1 + 2
+ val x = 1 - 2
+ val x = 1 / 2
+ val x = 1 * 2
+ val x = 1 % 2
+!/sc!
+&&,||,! *scala-qr-logical*
+ Basic logical operations
+!sc!
+ if (that && theother)
+ else if (that || theother)
+ else if (!that)
+!/sc!
+&,|,^,~ *scala-qr-bitwise*
+ Basic bitwise operations
+!sc!
+ val x = 4 & 1 // bitwise AND
+ val x = 4 | 1 // bitwise OR
+ val x = 4 ^ 1 // bitwise XOR
+ val x = ~4 // bitwise XOR
+!/sc!
+<<,>>,>>> *scala-qr-bitwise-shift*
+ Basic bitwise shift operations
+!sc!
+ val x = 4 << 1 // left shift
+ val x = 4 >> 1 // right shift
+ val x = 4 >>> 1 // unsigned right shift
+!/sc!
+>,<,<=,>=,==,!= *scala-qr-relational*
+ Relation operations
+!sc!
+ val x = a < b
+ val x = a > b
+ val x = a <= b
+ val x = a >= b
+ val x = a == b
+ val x = a != b
+!/sc!
+ NOTE: Scala does the right thing with relational operations. In Java,
+ there's this stupid idea that "==" means something different if you have a
+ primitive type or an object type, but in Scala relational operators are
+ uniform.
+
+ If you do want to check the value of a reference to an object, you must
+ use different operations:
+!sc!
+ val x = a eq b
+ val x = a neq b
+!/sc!
+
+==============================================================================
+5. Rich Operation *scala-qr-rich-operation* {{{1
+------------------------------------------------------------------------------
+
+Rich operators come in as wrappers around existing class types using implicit
+conversion.
+!sc!
+ RichBoolean
+ RichByte
+ RichChar
+ RichDouble
+ RichException
+ RichFloat
+ RichInt
+ RichLong
+ RichShort
+ RichUnit
+!/sc!
+You can thus do things like:
+!sc!
+ 0 max 5 // 5
+ 0 min 5 // 0
+ -2.7 abs // 2.7
+ -2.7 round // -3L
+ 1.5 isInfinity // false
+ (1.0 / 0) isInfinity // true
+ 4 to 6 // Range(4,5,6)
+ "nick" capitalize // "Nick"
+ "nicolas" drop 2 // "colas"
+!/sc!
+
+==============================================================================
+6. Literals *scala-qr-literals* {{{1
+------------------------------------------------------------------------------
+
+Integer literals *scala-qr-integer-literals*
+!sc!
+ val dec = 31 // decimal integer
+ val hex = 0xFFFF // hex integer
+ val long = 31L // long ("I" or "L")
+ val little: Short = 367 // short
+ val littler: Byte = 38 // byte
+!/sc!
+Floating point literals *scala-qr-float-literals*
+!sc!
+ val double = 1.2345 // double
+ val e = 1.234e4 // double ("e" or "E")
+ val float = 1.234f // float ("f" or "F")
+!/sc!
+Character and String literals *scala-qr-string-literals*
+!sc!
+ val aChar = 'D' // char
+ val unicode = '\u0043' // unicode char
+ val string = "string" // string
+ val s = """it's 'you'""" // raw string (it's 'you')
+!/sc!
+ Some literals with special meaning
+
+ \n line feed (\u000A)
+ \b backspace (\u0008)
+ \t tab (\u0009)
+ \f form feed (\u000C)
+ \r carriage return (\u000D)
+ \" double quote (\u0022)
+ \' single quote (\u0027)
+ \\ backslash (\u005C)
+
+Boolean literals *scala-qr-boolean-literals*
+!sc!
+ val bool = true // true | false
+!/sc!
+
+==============================================================================
+7. Type Information *scala-qr-typeinfo* {{{1
+------------------------------------------------------------------------------
+
+Type checking *scala-qr-type-checking*
+ Allows you to test the type of any object instance against a given class
+ type
+!sc!
+ "abc".isInstanceOf[String] // == true
+!/sc!
+Type casting *scala-qr-type-casting*
+ Allows you to cast any type to any other type
+!sc!
+ 3.asInstanceOf[Double] // == 3.0 (as double)
+!/sc!
+Runtime representation *scala-qr-runtime-representation*
+ Lets you get class type information at runtime
+!sc!
+ classOf[String] // java.lang.Class[String] = class java.lang.String
+!/sc!
+
+==============================================================================
+8. Packaging *scala-qr-packaging* {{{1
+------------------------------------------------------------------------------
+
+Import *scala-qr-import*
+!sc!
+ import java.awt._ // All classes under java.awt
+ import java.io.File
+ import java.io.File._ // all of File's static methods
+ import java.util.{Map, HashMap} // only the two classes
+
+ def doit() = {
+ import java.math.BigDecimal.{ONE}
+ println(ONE)
+ }
+
+ import java.math.BigDecimal.{
+ ONE => _, // Exclude ONE
+ ZERO => JZERO // Rename ZERO to JZERO
+ }
+ println(JZERO)
+!/sc!
+ NOTE: Import statements are relative, not absolute. To specify an
+ absolute path, start with _root_.
+!sc!
+ import _root_.scala.collectionsjcl._
+!/sc!
+Pacakges *scala-qr-packages*
+ Filenames don't have to match the type names, the package structure does
+not have to match the directory structure. So you an define packages in files
+independent of their "physical" location.
+!sc!
+ package com.xtech.scala
+ package com {
+ package scala {
+ class A
+ }
+ package util {
+ class B
+ package file {
+ class C
+ }
+ }
+ }
+!/sc!
+
+==============================================================================
+9. Tuples *scala-qr-tuples* {{{1
+------------------------------------------------------------------------------
+
+Tuples are immutable and can contain different types of elements.
+!sc!
+ val nena = (99, "Luftballons", "1983")
+ println(nena._1)
+ println(nena._2)
+!/sc!
+
+Modelines: {{{1
+vim:tw=78:ts=4:ft=help:fdm=marker:fdl=0
View
1  bundle/syntax_scala/ftdetect/scala.vim
@@ -0,0 +1 @@
+au BufRead,BufNewFile *.scala set filetype=scala
View
116 bundle/syntax_scala/ftplugin/scala.vim
@@ -0,0 +1,116 @@
+
+setlocal textwidth=140
+setlocal shiftwidth=2
+setlocal softtabstop=2
+setlocal expandtab
+setlocal formatoptions=tcqr
+
+"
+" FuzzyFinder stuff
+"
+"
+" SanitizeDirForFuzzyFinder()
+"
+" This is really just a convenience function to clean up any stray '/'
+" characters in the path, should they be there.
+"
+function! scala#SanitizeDirForFuzzyFinder(dir)
+ let dir = expand(a:dir)
+ let dir = substitute(dir, '/\+$', '', '')
+ let dir = substitute(dir, '/\+', '/', '')
+
+ return dir
+endfunction
+
+"
+" GetDirForFuzzyFinder()
+"
+" Given a directory to start 'from', walk up the hierarchy, looking for a path
+" that matches the 'addon' you want to see.
+"
+" If nothing can be found, then we just return the 'from' so we don't really get
+" the advantage of a hint, but just let the user start from wherever he was
+" starting from anyway.
+"
+function! scala#GetDirForFuzzyFinder(from, addon)
+ let from = scala#SanitizeDirForFuzzyFinder(a:from)
+ let addon = expand(a:addon)
+ let addon = substitute(addon, '^/\+', '', '')
+ let found = ''
+ " If the addon is right here, then we win
+ if isdirectory(from . '/' . addon)
+ let found = from . '/' . addon
+ else
+ let dirs = split(from, '/')
+ if !has('win32') && !has('win64')
+ let dirs[0] = '/' . dirs[0]
+ endif
+ " Walk up the tree and see if it's anywhere there
+ for n in range(len(dirs) - 1, 0, -1)
+ let path = join(dirs[0:n], '/')
+ if isdirectory(path . '/' . addon)
+ let found = path . '/' . addon
+ break
+ endif
+ endfor
+ endif
+ " If we found it, then let's see if we can go deeper
+ "
+ " For example, we may have found component_name/include
+ " but what if that directory only has a single directory
+ " in it, and that subdirectory only has a single directory
+ " in it, etc... ? This can happen when you're segmenting
+ " by namespace like this:
+ "
+ " component_name/include/org/vim/CoolClass.h
+ "
+ " You may find yourself always typing '' from the
+ " 'include' directory just to go into 'org/vim' so let's
+ " just eliminate the need to hit the ''.
+ if found != ''
+ let tempfrom = found
+ let globbed = globpath(tempfrom, '*')
+ while len(split(globbed, "\n")) == 1
+ let tempfrom = globbed
+ let globbed = globpath(tempfrom, '*')
+ endwhile
+ let found = scala#SanitizeDirForFuzzyFinder(tempfrom) . '/'
+ else
+ let found = from
+ endif
+
+ return found
+endfunction
+
+"
+" GetTestDirForFuzzyFinder()
+"
+" Now overload GetDirForFuzzyFinder() specifically for the test directory (I'm
+" really only interested in going down into test/src 90% of the time, so let's
+" hit that 90% and leave the other 10% to couple of extra keystrokes)
+"
+function! scala#GetTestDirForFuzzyFinder(from)
+ return scala#GetDirForFuzzyFinder(a:from, 'src/test/scala/')
+endfunction
+
+"
+" GetMainDirForFuzzyFinder()
+"
+" Now overload GetDirForFuzzyFinder() specifically for the main directory.
+"
+function! scala#GetMainDirForFuzzyFinder(from)
+ return scala#GetDirForFuzzyFinder(a:from, 'src/main/scala/')
+endfunction
+
+"
+" GetRootDirForFuzzyFinder()
+"
+" Now overload GetDirForFuzzyFinder() specifically for the root directory.
+"
+function! scala#GetRootDirForFuzzyFinder(from)
+ return scala#GetDirForFuzzyFinder(a:from, 'src/../')
+endfunction
+
+nnoremap <buffer> <silent> ,ft :FufFile <c-r>=scala#GetTestDirForFuzzyFinder('%:p:h')<cr><cr>
+nnoremap <buffer> <silent> ,fs :FufFile <c-r>=scala#GetMainDirForFuzzyFinder('%:p:h')<cr><cr>
+nnoremap <buffer> <silent> ,fr :FufFile <c-r>=scala#GetRootDirForFuzzyFinder('%:p:h')<cr><cr>
View
78 bundle/syntax_scala/indent/README
@@ -0,0 +1,78 @@
+Scala Indent file for Vim
+=========================
+
+You can check 'testfile.scala' in this directory to see what I'm testing
+against. I'm mostly just trying to fit the major conventions that people would
+code in with Scala, and not all of the possibilities - life's too short for that
+and I'd rather be writing Scala code than Vim indent code.
+
+With that said, if there's something you're passionate about and you want it to
+be properly indented, and you can't hack it in yourself, then feel free to drop
+me a line and we'll fight about it.
+
+You'll see the following comments in 'testfile.scala':
+
+ /**
+ * The following stuff doesn't work, but honestly, it's pretty
+ * pathological stuff... format your code differently.
+ *
+ * ---- 1. ----
+ *
+ * if (b) 1
+ * else
+ * if (c) 2
+ * else 3
+ *
+ * Do this instead:
+ *
+ * if (b) 1
+ * else {
+ * if (c) 2
+ * else 3
+ * }
+ *
+ *
+ * ---- 2. ----
+ *
+ * if (b) 1
+ * else
+ * if (c)
+ * 2
+ * else 3
+ *
+ * Do this instead:
+ *
+ * if (b) 1
+ * else {
+ * if (c) 2
+ * else 3
+ * }
+ *
+ * or this...
+ *
+ * if (b) 1
+ * else {
+ * if (c)
+ * 2
+ * else
+ * 3
+ * }
+ *
+ * ---- 3. ----
+ *
+ * if (b) 1
+ * else {
+ * if (c)
+ * 2
+ * else 3
+ * }
+ *
+ * Do the same as in number 2
+ */
+
+In other words, for the forseeable future... do something different to fix the
+cases that don't work. :)
+
+If you've got any questions about what's defined now, you can reach me at
+http://derekwyatt.org.
+
View
593 bundle/syntax_scala/indent/scala.vim
@@ -0,0 +1,593 @@
+" Vim indent file
+" Language : Scala (http://scala-lang.org/)
+" Original Author : Stefan Matthias Aust
+" Modifications by : Derek Wyatt
+" Last Change: 2011 Mar 19 (Derek Wyatt)
+
+"if exists("b:did_indent")
+" finish
+"endif
+"let b:did_indent = 1
+
+setlocal indentexpr=GetScalaIndent()
+setlocal indentkeys=0{,0},0),!^F,<>>,o,O,e,=case,<CR>
+setlocal autoindent
+
+"if exists("*GetScalaIndent")
+" finish
+"endif
+
+let s:defMatcher = '\%(\%(private\|protected\)\%(\[[^\]]*\]\)\?\s\+\|abstract\s\+\|override\s\+\)*\<def\>'
+let s:funcNameMatcher = '\w\+'
+let s:typeSpecMatcher = '\%(\s*\[\_[^\]]*\]\)'
+let s:defArgMatcher = '\%((\_.\{-})\)'
+let s:returnTypeMatcher = '\%(:\s*\w\+' . s:typeSpecMatcher . '\?\)'
+let g:fullDefMatcher = '^\s*' . s:defMatcher . '\s\+' . s:funcNameMatcher . '\s*' . s:typeSpecMatcher . '\?\s*' . s:defArgMatcher . '\?\s*' . s:returnTypeMatcher . '\?\s*[={]'
+
+function! scala#ConditionalConfirm(msg)
+ if 0
+ call confirm(a:msg)
+ endif