Permalink
Browse files

initial upload

  • Loading branch information...
0 parents commit 15c70068c6db03e16d089bcc8e4d6ee66ed2f49e @jboner committed Jun 23, 2008
@@ -0,0 +1,12 @@
+Copyright (C) 2007-2008 Scala OTP Team
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * The names of its contributors may not, in any way, be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
@@ -0,0 +1,6 @@
+# For Unix:
+# mvn -o <target> |sed -e s/\\[WARNING\\][[:space:]]//g |grep -v "Finished at"
+
+install:
+ mvn -o scala:testCompile |sed -e 's/\[INFO\] //g' |sed -e 's/\[WARNING\] //g' |grep -v "Finished at" |grep -v "Total time"
+
@@ -0,0 +1,214 @@
+--- OVERVIEW ---
+Scala Actors Behavior Module
+
+Implements Erlang-style Behaviors for Scala; Supervisor, GenericServer, GenericEvent and GenericFiniteStateMachine allowing creating fault-tolerant actor-based enterprise systems.
+
+The implementation consists of four main abstractions;
+
+* Supervisor -- The Supervisor manages hierarchies of Scala actors and provides fault-tolerance in terms of different restart
+semantics. The configuration and semantics is almost a 1-1 port of the Erlang Supervisor implementation, explained
+here: http://www.erlang.org/doc/design_principles/sup_princ.html, read this document in order to understand how to
+configure the Supervisor properly.
+
+* GenericServer -- The GenericServer (which subclasses Actor) is a trait that forms the base for a server to be managed by a Supervisor.
+The GenericServer is wrapped by a GenericServerContainer instance providing a necessary indirection needed to be able to
+fully manage the life-cycle of the GenericServer.
+
+* GenericEvent -- TBD
+
+* GenericFiniteStateMachine -- TBD
+
+--- CHECK OUT ---
+The SCM system used is Git.
+
+1. Download and install Git (google git).
+2. Invoke 'git clone git@github.com:jboner/scala-supervisor.git'.
+
+--- BUILD ---
+The build system used is Maven.
+
+1. Download and install Maven 2.
+2. Step into the root dir 'scala-supervisor'.
+3. Invoke 'mvn install'
+
+This will build the project, run all tests, create a jar and upload it to your local Maven repository ready for use.
+
+--- RUNTIME DEPENDENCIES ---
+1. Scala 2.7.1-final
+2. SLF4J 1.5.2
+3. LogBack Classic 0.9.9
+
+--- USAGE ---
+Here is a small step-by-step runnable tutorial on how to create a server, configure it, use it, hotswap its
+implementation etc. For more details on the API, look at the code or the tests.
+
+You can find this code in the sample.scala file in the root directory. Run it by invoking 'scala -cp
+target/supervisor-0.3.jar:<path to slf4j and logback jars> sample.scala'
+
+// =============================================
+// 1. Import statements and Server messages
+
+import scala.actors._
+import scala.actors.Actor._
+
+import scala.actors.behavior._
+import scala.actors.behavior.Helpers._
+
+sealed abstract class SampleMessage
+case object Ping extends SampleMessage
+case object Pong extends SampleMessage
+case object OneWay extends SampleMessage
+case object Die extends SampleMessage
+
+// =============================================
+// 2. Create the GenericServer by extending the GenericServer trait and override the 'body' method
+
+class SampleServer extends GenericServer {
+
+ // This method implements the core server logic and naturally has to be overridden
+ override def body: PartialFunction[Any, Unit] = {
+ case Ping =>
+ println("Received Ping"); reply(Pong)
+
+ case OneWay =>
+ println("Received OneWay")
+
+ case Die =>
+ println("Received Die..dying...")
+ throw new RuntimeException("Received Die message")
+ }
+
+ // GenericServer also has some callback life-cycle methods, such as init(..) and shutdown(..)
+}
+
+// =============================================
+// 3. Wrap our SampleServer in a GenericServerContainer and give it a name to be able to refer to it later.
+
+object sampleServer1 extends GenericServerContainer("sample1", () => new SampleServer)
+object sampleServer2 extends GenericServerContainer("sample2", () => new SampleServer)
+
+// =============================================
+// 4. Create a Supervisor configuration (and a SupervisorFactory) that is configuring our SampleServer (takes a list of
+'Worker' configurations, one or many)
+
+object factory extends SupervisorFactory {
+ override protected def getSupervisorConfig: SupervisorConfig = {
+ SupervisorConfig(
+ RestartStrategy(AllForOne, 3, 10000),
+ Worker(
+ sampleServer1,
+ LifeCycle(Permanent, 1000)) ::
+ Worker(
+ sampleServer2,
+ LifeCycle(Permanent, 1000)) ::
+ Nil)
+ }
+}
+
+// =============================================
+// 5. Create a new Supervisor with the custom factory
+
+val supervisor = factory.newSupervisor
+
+// =============================================
+// 6. Start the Supervisor (which starts the server(s))
+
+supervisor ! Start
+
+// =============================================
+// 7. Try to send a one way asyncronous message to our servers
+
+sampleServer1 ! OneWay
+
+// Try to get sampleServer2 from the Supervisor before sending a message
+supervisor.getServer("sample2") match {
+ case Some(server2) => server2 ! OneWay
+ case None => println("server [sample2] could not be found")
+}
+
+// =============================================
+// 8. Try to send an asyncronous message - receive a future - wait 100 ms (time-out) for the reply
+
+val future = sampleServer1 !! Ping
+val reply1 = future.receiveWithin(100) match {
+ case Some(reply) =>
+ println("Received reply: " + reply)
+ case None =>
+ println("Did not get a reply witin 100 ms")
+}
+
+// =============================================
+// 9. Try to send a message (Die) telling the server to kill itself (throw an exception)
+
+sampleServer1 ! Die
+
+// =============================================
+// 10. Send an asyncronous message and wait on a future. If it times out -> use error handler (in this case throw an
+exception). It is likely that this call will time out since the server is in the middle of recovering from failure.
+
+val reply2 = try {
+ sampleServer1 !!! (Ping, throw new RuntimeException("Time-out"), 10) // time out is set to 10 ms (very low on purpose)
+
+} catch { case e => println("Expected exception: " + e.toString); Pong }
+
+// =============================================
+// 11. Server should be up again. Try the same call again
+
+val reply3 = try {
+ sampleServer1 !!! (Ping, throw new RuntimeException("Time-out"), 1000)
+} catch { case e => println("Expected exception: " + e.toString); Pong }
+
+// Also check server number 2
+sampleServer2 ! Ping
+
+// =============================================
+// 11. Try to hotswap the server implementation
+
+sampleServer1.hotswap(Some({
+ case Ping =>
+ println("Hotswapped Ping")
+}))
+
+// =============================================
+// 12. Try the hotswapped server out
+
+sampleServer1 ! Ping
+
+// =============================================
+// 13. Hotswap again
+
+sampleServer1.hotswap(Some({
+ case Pong =>
+ println("Hotswapped again, now doing Pong")
+ reply(Ping)
+}))
+
+// =============================================
+// 14. Send an asyncronous message that will wait on a future. Method returns an Option[T] => if Some(result) -> return
+result, if None -> print out an info message (or throw an exception or do whatever you like...)
+
+val reply4 = (sampleServer1 !!! Pong).getOrElse({println("Time out when sending Pong"); Ping})
+
+// Same invocation with pattern matching syntax.
+
+val reply5 = sampleServer1 !!! Pong match {
+ case Some(result) => result
+ case None => println("Time out when sending Pong"); Ping
+}
+
+// =============================================
+// 15. Hotswap back to original implementation by passing in None
+
+sampleServer1.hotswap(None)
+
+// =============================================
+// 16. Test the final hotswap by sending an async message
+
+sampleServer1 ! Ping
+
+// =============================================
+// 17. Shut down the supervisor and its server(s)
+
+supervisor ! Stop
+
+
Oops, something went wrong.

0 comments on commit 15c7006

Please sign in to comment.