Tokens and TokenDispenser

The NumberDispenser developed so far is a generic object that dispenses numbers. In and of itself, it does not relate directly to the problem at hand. We need to encapsulate it as part of domain objects that are more natural for the Virtual Queuing application that we are developing.

In today’s blog we will introduce two such domain objects that make more sense in our domain. We will show how to create relationships between these objects and how to use fine grained access modifiers to control the visibility and ownership of these objects.

A Token is something that you take when you get in a queue. A Token usually has a number that is used to call out which token is being served. The TokenDispenser dispenses tokens. Let’s see the modified class –

[sourcecode language=”scala”]
package com.scoovyfoo.domobj

import actors.Actor
import actors.Actor.self

class TokenDispenser(startingNumber: Int) {
NumberDispenser.start()

private object NumberDispenser extends Actor {
private def numberStream(num: Int): Stream[Int] = num #:: numberStream(num + 1)

private var nextNumberStream = numberStream(startingNumber)

def act() {
loop {
react {
case ("DISPENSE", actor: Actor) => {
actor ! nextNumberStream.head
nextNumberStream = nextNumberStream.tail
}
case ("RESET", resetTo: Int) => nextNumberStream = numberStream(resetTo)
case ("PEEK", actor: Actor) => actor ! nextNumberStream.head
}
}
}
}

case class Token private[TokenDispenser](number: Int) {
private[TokenDispenser] def copy: Token = throw new Error
}

def reset(resetTo: Int) = {
NumberDispenser !("RESET", resetTo)
this
}

def dispense: Token = {
NumberDispenser !("DISPENSE", self)
self.receive {
case nextNum: Int => Token(nextNum)
}
}

// Just peeks at the next number without getting it
def peek: Int = {
NumberDispenser !("PEEK", self)
self.receive {
case nextNum: Int => nextNum
}
}

}

[/sourcecode]

Our NumberDispenser class has no use outside of the TokenDispenser class. So the first thing we will do is to make the NumberDispenser class a private inner (or nested class) of TokenDispenser. Since the class is a private class of the TokenDispenser class, it can only be used by the TokenDispenser class.

Next we create a Token class as an inner class of TokenDispenser. We make Token a case class. A case class in scala is a special type of class for which the compiler produces a lot of supporting code under the hood. An important piece of this generated code allows us to do pattern matching on objects of case classes without having to write any boiler plate code to compare two tokens. We will need token comparison later in the system so it makes sense for Token to be a case class. Besides enabling pattern matching the Scala compiler also generates code that makes it very convenient to use case classes

  1. It generates a factory method with the name of the class. So we can use Token(5) for creating a token object instead of the slightly longer new Token(5). So in the dispense method we create the Tokens by using just its compiler generated factory method.[sourcecode language=”scala”]
    def dispense: Token = {
    NumberDispenser !("DISPENSE", self)
    self.receive {
    case nextNum: Int => Token(nextNum)
    }
    }
    [/sourcecode]
  2. The compiler also makes all the class parameters listed with the Token class as fields of the class. So they are available for us to consume later. For example, number automatically becomes a val numberfield and we can easily access it later. In the code snippet below from our test case, we are accessing the number field directly.[sourcecode language=”scala”]
    test("dispense") {
    assert(1304 == tokenDispenser.dispense.number)
    assert(1305 == tokenDispenser.dispense.number)
    assert(1306 == tokenDispenser.dispense.number)

    for (i <- 1307 to 101307)
    assert(i == tokenDispenser.dispense.number)
    }
    [/sourcecode]

  3. The compiler adds an natural implementation of the toString, hashCode and equals method. This is convenient if we want to print, hash and compare two objects of a case class.
  4. Finally the compiler also adds a copy method for the class. This method is convenient if we need to make a copy of the object that looks exactly same as the original object but differs in one or two fields.

Now lets discuss the reason for making the case class an inner class of TokenDispenser. We do not want Tokens to be created anywhere else in the system but by only a TokenDispenser. Such restriction is possible only by restricting the access to the primary constructor for our Token class to its dispenser. This is achieved by making the Token class an inner class of TokenDispenser AND by modifying the primary constructor to be private with access up to its enclosing class “TokenDispenser”. Scala allows the access modifiers to be qualified by putting the qualifiers in square brackets and that is what we are doing when we make the primary constructor for the Token class private up to the TokenDIspenser class by listing it as private[TokenDispenser]. Also note that since Scala’s compiler automatically generates the primary constructor, the only way to specify this restriction is by adding it to the definition of the Token class as can be seen below. Now if any code outside of the TokenDispenser class tries to instantiate a Token object they will get a compilation error.

[sourcecode language=”scala”]
case class Token private[TokenDispenser](number: Int) {
private[TokenDispenser] def copy: Token = throw new Error
}
[/sourcecode]

For example if we add the following code to our test class:

[sourcecode language=”scala”]
val t = tokenDispenser.Token(5)
[/sourcecode]

We will get this error

[sourcecode language=”text”]
TokenDispenserTest.scala:94: error: constructor Token in class Token cannot be accessed in class TokenDispenserTest
[INFO] val t = tokenDispenser.Token(5)
[/sourcecode]

The only other item of interest in this Token class is the copy method. Remember a case class automatically generates a copy method and makes it public. So even though we went through all the trouble to make the constructor private, any one can call the copy method and get a fresh new copy of the the Token class. In order to prevent that, we are explicitly providing a copy method that is both private up to the TokenDispenser class and not only that it throws an Error. So if we were to add the following code to our test case –

[sourcecode language=”scala”]
val t2 = t.copy (number = 4)
[/sourcecode]

We will get the following error –

[sourcecode language=”text”]
[ERROR]TokenDispenserTest.scala:101: error: value copy is not a member of TokenDispenserTest.this.tokenDispenser.Token
[INFO] val t2 = t.copy (number = 4)
[/sourcecode]

Testing

Here is the modified test case to test our TokenDispenser and Token class. It is similar to the NumberDispenser test class except we have modified the multithreaded test case to asset that we do not have duplicated numbers in any Token even though multiple threads might be requesting tokens from the same dispenser at the same time.

[sourcecode language=”scala”]
package Scala.com.scoovyfoo.domobj

import org.scalatest.{BeforeAndAfter, FunSuite}
import org.scalatest.junit.JUnitRunner
import org.junit.runner.RunWith
import actors.Actor._
import actors.Actor.self
import actors.Actor
import com.scoovyfoo.domobj.TokenDispenser

/**
*
* User: Anupam Chandra
*/

@RunWith(classOf[JUnitRunner])
class TokenDispenserTest extends FunSuite with BeforeAndAfter {
private val tokenDispenser = new TokenDispenser(100)

before {
tokenDispenser.reset(1304)
}

test("dispense") {
assert(1304 == tokenDispenser.dispense.number)
assert(1305 == tokenDispenser.dispense.number)
assert(1306 == tokenDispenser.dispense.number)

for (i <- 1307 to 101307)
assert(i == tokenDispenser.dispense.number)
}

test("reset") {
assert(1 == tokenDispenser.reset(1).dispense.number)
assert(2 == tokenDispenser.dispense.number)
assert(3 == tokenDispenser.dispense.number)
}

test("MultiThreaded") {
import collection.mutable.Map

val aMap: Map[tokenDispenser.Token, String] = Map()
// Create the first thread and make it start by sending a message of type tuple that has the "START" string and
// the requesting thread
val actorOne = actor {
react {
case ("START", requester: Actor) => {
//
for (i <- 1 to 100) {
requester ! (tokenDispenser.dispense, "ActorOne" )
}
requester ! "EXIT"
}
}
}
// Create the second thread and start it just like the first thread
val actorTwo = actor {
react {
case ("START", requester: Actor) =>{
for (i <- 1 to 100) {
requester ! (tokenDispenser.dispense, "ActorTwo")
}
requester ! "EXIT"
}
}
}

actorOne ! ("START", self)
actorTwo ! ("START", self)
var numActorsRunning = 2

do {
receive {
case "EXIT" => numActorsRunning -= 1
case (t: tokenDispenser.Token, s: String) => {
intercept[NoSuchElementException] {
try{aMap(t)} catch {case ex:NoSuchElementException => {aMap += (t -> s); throw ex} }
}
}
}
} while (numActorsRunning > 0)

assert(200 == aMap.size)

}

test("Peek") {
assert(1304 == tokenDispenser.peek)
assert(1304 == tokenDispenser.peek)
assert(1304 == tokenDispenser.peek)
assert(tokenDispenser.dispense != tokenDispenser.dispense)
assert(1306 == tokenDispenser.peek)
val actorTwo = actor {
tokenDispenser.dispense
tokenDispenser.dispense
tokenDispenser.dispense

}
// Let the other thread finish so sleep for a while.
Thread.sleep(100)
assert(1309 == tokenDispenser.peek)
}

}

[/sourcecode]

Consider the “multi threaded” test case. In previous blogs we were just printing out the numbers from multiple threads and then manually validating that no two numbers were duplicates. In this modified test case, we are using another Scala provided collections data structure called Map. A Map correlates a key to a value. We will use the token  as the key and a made up thread name as the value.  We start multiple threads, each taking a token from the same token dispenser and passing it back to us. Once we get the token from either of the thread, we look in our Map to see if that token exists in the map or not. It should not if our TokenDispenser is thread safe. So in every case, when we check for existence of a token in the map class, we expect a NoSuchElementException. When we do get that exception, we catch it and add the token along with the thread name  to the map a re-throw the exception. ScalaTest provides a convenient mechanism of listing that we are expecting an exception. It does that by providing an intercept method that we create by parameterizing it on the NoSuchElementException and passing a function value as its argument. The intercept method will ensure that the exception is thrown, if not it will fail the test case.

Our previous version of this test case, simply started the two actors and all they did was request a number from the number dispenser and printed that number out. However, this modified version of the test case, actually passes the token back to the thread that started it; in this case, the thread that is running the test case. The way this communication happens is via passing messages between the originating test thread and the actor threads. The originating thread after creating the actors sends a “START” message to them. It also sends a self reference to them which is then used by the worker threads to pass back the token that they got. Once the worker threads are done with their loop, they send an “EXIT” message back to the originating thread. When the originating thread gets all EXITS, it comes out of its reveive loop ending the test case.

There are two types of messages that the originating thread can handle, an EXIT message and a message that passes the token along with the thread name back. We match the correct message and if the message is of latter type we check in the map to see it the token that we received exists in the map, it should not and so we insert it. Since our Token class is a case class it makes it easy to do pattern matching and equality check in the map.

Note that we are using a mutable map. By default Scala provides an immutable map, but that is of limited value for us since we are going to request hundreds of token and we need to add them to the map as they arrive. A mutable map allows us to do just that.

Conclusion

In this blog we introduced domain objects that are more meaningful for the problem we are solving and provide the correct abstraction. We saw how to restrict the scope of a class and how to use correct access modifiers to restrict the use of these classes.

At this point we are ready to put an interface on to our Token Dispenser. We will start with a simple web interface and then add other interfaces such as mobile interfaces for both iOs and Androis.

Leave a Reply

Your email address will not be published. Required fields are marked *