Skip to content
laforge49 edited this page Dec 9, 2011 · 2 revisions

Any time you do I/O you will likely want to do it asynchronously, as otherwise the current thread will be tied up until the operation completes and any number of Actors will also become unresponsive.

The LoadFile actor is a good case in point. This actor reads (hopefully short) files but remains oblivious to how it is being run (asynchronously/synchronously):

case class LoadFile(file: File)

class FileLoader
  extends Actor {

  bind(classOf[LoadFile], loadFile)

  def loadFile(msg: AnyRef, rf: Any => Unit) {
    val file = msg.asInstanceOf[LoadFile].file
    val size = file.length
    val fis = new FileInputStream(file)
    val dis = new DataInputStream(fis)
    val bytes = new Array[Byte](size.asInstanceOf[Int])
    dis.readFully(bytes)
    rf(bytes)
  }
}

By defining a component and component factory for FileLoader, we can turn FileLoader into an asynchronous services that can be part of a system services composite:

class FileLoaderComponent(actor: Actor)
  extends Component(actor) {

  val fileLoader = new FileLoader
  bindMessageLogic(classOf[LoadFile], new Forward(fileLoader))

  override def open {
    super.open
    fileLoader.setExchangeMessenger(systemServices.newAsyncMailbox)
  }
}

class FileLoaderComponentFactory 
  extends ComponentFactory {

  override def instantiate(actor: Actor) = new FileLoaderComponent(actor)
}

Here's the test which includes the LoadFile service:

val systemServices = SystemServices(new FileLoaderComponentFactory)
try {
  val shortFileLoader = new ShortFileLoader
  shortFileLoader.setExchangeMessenger(systemServices.newAsyncMailbox)
  val bytes = Future(shortFileLoader, DoIt()).asInstanceOf[Array[Byte]]
  val bais = new ByteArrayInputStream(bytes)
  val isr = new InputStreamReader(bais)
  val br = new BufferedReader(isr)
  val line = br.readLine
  println(line)
} finally {
  systemServices.close
}

And here is the driver which uses the service:

case class DoIt()

class ShortFileLoader 
  extends Actor {

  bind(classOf[DoIt], doit)

  def doit(msg: AnyRef, rf: Any => Unit) {
    val cwd = new File(".")
    println("cwd = " + cwd.getCanonicalPath)
    val file = new File("aShortTestFile.txt")
    println("test file exists = " + file.exists)
    systemServices(LoadFile(file))(rf)
  }
}

FileLoader

FileLoaderTest

Clone this wiki locally