Migration Guide 0.8.x to 0.9.x

Migration Guide 0.8.x to 0.9.x

This document describes between the 0.8.x and the 0.9 release.

Background for the new ActorRef

In the work towards 0.9 release we have now done a major change to how Actors are created. In short we have separated identity and value, created an ‘ActorRef’ that holds the actual Actor instance. This allows us to do many great things such as for example:

  • Create serializable, immutable, network-aware Actor references that can be freely shared across the network. They “remember” their origin and will always work as expected.
  • Not only kill and restart the same supervised Actor instance when it has crashed (as we do now), but dereference it, throw it away and make it eligible for garbage collection.
  • etc. much more

These work very much like the ‘PID’ (process id) in Erlang.

These changes means that there is no difference in defining Actors. You still use the old Actor trait, all methods are there etc. But you can’t just new this Actor up and send messages to it since all its public API methods are gone. They now reside in a new class; ‘ActorRef’ and use need to use instances of this class to interact with the Actor (sending messages etc.).

Here is a short migration guide with the things that you have to change. It is a big conceptual change but in practice you don’t have to change much.

Creating Actors with default constructor

From:

val a = new MyActor
a ! msg

To:

import Actor._
val a = actorOf[MyActor]
a ! msg

You can also start it in the same statement:

val a = actorOf[MyActor].start

Creating Actors with non-default constructor

From:

val a = new MyActor(..)
a ! msg

To:

import Actor._
val a = actorOf(new MyActor(..))
a ! msg

Use of ‘self’ ActorRef API

Where you have used ‘this’ to refer to the Actor from within itself now use ‘self’:

self ! MessageToMe

Now the Actor trait only has the callbacks you can implement: * receive * postRestart/preRestart * init/shutdown

It has no state at all.

All API has been moved to ActorRef. The Actor is given its ActorRef through the ‘self’ member variable. Here you find functions like: * !, !!, !!! and forward * link, unlink, startLink, spawnLink etc * makeTransactional, makeRemote etc. * start, stop * etc.

Here you also find fields like * dispatcher = ... * id = ... * lifeCycle = ... * faultHandler = ... * trapExit = ... * etc.

This means that to use them you have to prefix them with ‘self’, like this:

self ! Message

However, for convenience you can import these functions and fields like below, which will allow you do drop the ‘self’ prefix:

class MyActor extends Actor {
  import self._
  id = ...
  dispatcher = ...
  spawnLink[OtherActor]
  ...
}

Serialization

If you want to serialize it yourself, here is how to do it:

val actorRef1 = actorOf[MyActor]

val bytes = actorRef1.toBinary

val actorRef2 = ActorRef.fromBinary(bytes)

If you are also using Protobuf then you can use the methods that work with Protobuf’s Messages directly.

val actorRef1 = actorOf[MyActor]

val protobufMessage = actorRef1.toProtocol

val actorRef2 = ActorRef.fromProtocol(protobufMessage)

Camel

Some methods of the se.scalablesolutions.akka.camel.Message class have been deprecated in 0.9. These are

package se.scalablesolutions.akka.camel

case class Message(...) {
  // ...
  @deprecated def bodyAs[T](clazz: Class[T]): T
  @deprecated def setBodyAs[T](clazz: Class[T]): Message
  // ...
}

They will be removed in 1.0. Instead use

package se.scalablesolutions.akka.camel

case class Message(...) {
  // ...
  def bodyAs[T](implicit m: Manifest[T]): T =
  def setBodyAs[T](implicit m: Manifest[T]): Message
  // ...
}

Usage example: .. code-block:: scala

val m = Message(1.4) val b = m.bodyAs[String]

Contents