Permalink
Browse files

Merge branch 'master' of https://github.com/ewiplayer/Scala-Investiga…

  • Loading branch information...
2 parents 75c5f22 + 89289f0 commit f34f5c08cb98416437108f97310502f88a6f6537 @derekwyatt committed Feb 27, 2011
Showing with 205 additions and 0 deletions.
  1. +144 −0 beginning-scala/XAction.scala
  2. +61 −0 beginning-scala/implicit.scala
View
144 beginning-scala/XAction.scala
@@ -0,0 +1,144 @@
+import scala.actors.Actor
+import Actor._
+import scala.actors.TIMEOUT
+
+case object GetInfo
+case class Info(i: Map[String, Int])
+case class SetInfo(n: String, v: Int)
+case class Update(n: String, f: Option[Int] => Int)
+case class BeginXAction(id: Int)
+case object CommitXAction
+case object RollbackXAction
+
+class Acct extends Actor {
+
+ private var info: Map[String, Int] = Map()
+ private var service = (normal, false)
+
+ private def normal: PartialFunction[Any, Unit] = {
+ case GetInfo => reply(Info(info))
+ case SetInfo(n, v) => info += n -> v
+ case Update(n, f) => info += n -> f(info.get(n))
+ case BeginXAction(id) => begin(id)
+ }
+
+ private def begin(xActionId: Int) {
+ val oldInfo = info // capture
+ val oldService = service
+ val tmp: PartialFunction[Any, Unit] = {
+ case TIMEOUT => { // Rollback
+ info = oldInfo
+ service = oldService
+ }
+ case (n, RollbackXAction) if n == xActionId => {
+ info = oldInfo
+ service = oldService
+ }
+ case (n, CommitXAction) if n == xActionId => { // Commit
+ service = oldService
+ }
+ case (n, v) if n == xActionId && normal.isDefinedAt(v) => normal(v)
+ }
+ service = (tmp, true)
+ }
+
+ def act = loop {
+ service match {
+ case (pf, false) => react(pf)
+ case (pf, true) => reactWithin(500)(pf)
+ }
+ }
+
+ this.start
+}
+
+object TestAcct {
+
+ def doTest() = {
+ val dpp = new Acct
+ dpp ! Update("Savings", v => (v getOrElse 0) + 1000)
+ dpp ! Update("Checking", v => (v getOrElse 0) + 100)
+
+ val archer = new Acct
+ archer ! Update("Savings", v => (v getOrElse 0) + 2000)
+ archer ! Update("Checking", v => (v getOrElse 0) + 50)
+
+ println("Initial balances:")
+ println("dpp: " + (dpp !? GetInfo))
+ println("archer: " + (archer !? GetInfo))
+
+ var xid = 1
+ def transfer(who: Actor, from: String, to: String, amount: Int): Boolean = {
+ xid += 1
+ who ! BeginXAction(xid)
+ who !? (500, (xid, GetInfo)) match {
+ case Some(Info(bal)) => {
+ if (bal.getOrElse(from, 0) > amount) {
+ who ! (xid, Update(from, v => (v getOrElse 0) - amount))
+ who ! (xid, Update(to, v => (v getOrElse 0) + amount))
+ who ! (xid, CommitXAction)
+ true
+ } else {
+ who ! (xid, RollbackXAction)
+ false
+ }
+ }
+ case _ => {
+ who ! (xid, RollbackXAction)
+ false
+ }
+ }
+ }
+ transfer(dpp, "Savings", "Checking", 700)
+ println("xfer 1 dpp: " + (dpp !? GetInfo))
+
+ transfer(dpp, "Savings", "Checking", 700)
+ println("xfer 2 dpp: " + (dpp !? GetInfo))
+
+ def transfer2(src: Actor, sact: String, dest: Actor, dact: String, amount: Int): Boolean = {
+ xid += 1
+ src ! BeginXAction(xid)
+ dest ! BeginXAction(xid)
+ (src !? (500, (xid, GetInfo)), dest !? (500, (xid, GetInfo))) match {
+ case (Some(Info(sbal)), Some(Info(dbal))) => {
+ dest ! (xid, Update(dact, v => (v getOrElse 0) + amount))
+ if (sbal.getOrElse(sact, 0) > amount) {
+ src ! (xid, Update(sact, v => (v getOrElse 0) - amount))
+ src ! (xid, CommitXAction)
+ dest ! (xid, CommitXAction)
+ true
+ } else {
+ src ! (xid, RollbackXAction)
+ dest ! (xid, RollbackXAction)
+ false
+ }
+ }
+ case _ => {
+ src ! (xid, RollbackXAction)
+ dest ! (xid, RollbackXAction)
+ false
+ }
+ }
+ }
+ transfer2(dpp, "Checking", archer, "Checking", 700)
+ println("XFer 700 dpp -> archer:")
+ println("dpp: " + (dpp !? GetInfo))
+ println("archer: " + (archer !? GetInfo))
+
+ transfer2(dpp, "Checking", archer, "Checking", 700)
+ println("Again, XFer 700 dpp -> archer:")
+ println("dpp: " + (dpp !? GetInfo))
+ println("archer: " + (archer !? GetInfo))
+
+ transfer2(dpp, "Checking", archer, "Checking", 10)
+ println("XFer 10 dpp -> archer:")
+ println("dpp: " + (dpp !? GetInfo))
+ println("archer: " + (archer !? GetInfo))
+ }
+}
+
+object Main {
+ def main(args: Array[String]) {
+ TestAcct.doTest
+ }
+}
View
61 beginning-scala/implicit.scala
@@ -0,0 +1,61 @@
+import java.util.Date
+
+object TimeHelpers {
+
+ case class TimeSpanBuilder(val len: Long) {
+ def seconds = TimeSpan(TimeHelpers.seconds(len))
+ def second = seconds
+ def minutes = TimeSpan(TimeHelpers.minutes(len))
+ def minute = minutes
+ def hours = TimeSpan(TimeHelpers.hours(len))
+ def hour = hours
+ def days = TimeSpan(TimeHelpers.days(len))
+ def day = days
+ def weeks = TimeSpan(TimeHelpers.weeks(len))
+ def week = weeks
+ }
+
+ def seconds(in: Long): Long = in * 1000L
+ def minutes(in: Long): Long = seconds(in) * 60L
+ def hours(in: Long): Long = minutes(in) * 60L
+ def days(in: Long): Long = hours(in) * 24L
+ def weeks(in: Long): Long = days(in) * 7L
+
+ implicit def longToTimeSpanBuilder(in: Long): TimeSpanBuilder =
+ TimeSpanBuilder(in)
+ implicit def intToTimeSpanBuilder(in: Int): TimeSpanBuilder =
+ TimeSpanBuilder(in)
+
+ def millis = System.currentTimeMillis
+ def now = millis
+
+ case class TimeSpan(millis: Long) extends Ordered[TimeSpan] {
+ def later = new Date(millis + TimeHelpers.millis)
+ def ago = new Date(TimeHelpers.millis - millis)
+ def +(in: TimeSpan) = TimeSpan(this.millis + in.millis)
+ def -(in: TimeSpan) = TimeSpan(this.millis - in.millis)
+ def compare(other: TimeSpan) = millis compare other.millis
+ }
+
+ object TimeSpan {
+ implicit def tsToMillis(in: TimeSpan): Long = in.millis
+ }
+
+ class DateMath(d: Date) {
+ def +(ts: TimeSpan) = new Date(d.getTime + ts.millis)
+ def -(ts: TimeSpan) = new Date(d.getTime - ts.millis)
+ }
+
+ implicit def dateToDM(d: Date) = new DateMath(d)
+}
+
+import TimeHelpers._
+
+println("1.day = " + 1.day)
+println("now = " + new Date() + ", (5.days + 2.hours).later = " +
+ (5.days + 2.hours).later)
+val d1 = new Date(now)
+println("now = " + d1 + ", now + 8.weeks = " + (d1 + 8.weeks))
+val d2 = new Date(7.days + 2.hours + 4.minutes)
+println("d2 = " + d2)
+println("now = " + new Date(now) + ", 5.minutes.ago = " + 5.minutes.ago)

0 comments on commit f34f5c0

Please sign in to comment.