diff --git a/LICENSE b/LICENSE index 0acc58cb79..4e1dd06320 100755 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ This software is licensed under the Apache 2 license, quoted below. -Copyright 2009 Scalable Solutions AB [http://scalablesolutions.se] +Copyright 2009-2010 Scalable Solutions AB [http://scalablesolutions.se] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of diff --git a/akka-core/src/main/scala/actor/Actor.scala b/akka-core/src/main/scala/actor/Actor.scala index b66131123d..8b4cb81836 100644 --- a/akka-core/src/main/scala/actor/Actor.scala +++ b/akka-core/src/main/scala/actor/Actor.scala @@ -73,10 +73,11 @@ object Actor extends Logging { val TIMEOUT = config.getInt("akka.actor.timeout", 5000) val SERIALIZE_MESSAGES = config.getBool("akka.actor.serialize-messages", false) - /** A Receive is the type that defines actor message behavior - * currently modeled as a PartialFunction[Any,Unit] + /** + * A Receive is a convenience type that defines actor message behavior currently modeled as + * a PartialFunction[Any, Unit]. */ - type Receive = PartialFunction[Any,Unit] + type Receive = PartialFunction[Any, Unit] private[actor] val actorRefInCreation = new scala.util.DynamicVariable[Option[ActorRef]](None) @@ -89,6 +90,10 @@ object Actor extends Logging { * actor ! message * actor.stop * + * You can create and start the actor in one statement like this: + *
+ * val actor = actorOf[MyActor].start + **/ def actorOf[T <: Actor: Manifest]: ActorRef = new LocalActorRef(manifest[T].erasure.asInstanceOf[Class[_ <: Actor]]) @@ -105,6 +110,10 @@ object Actor extends Logging { * actor ! message * actor.stop * + * You can create and start the actor in one statement like this: + *
+ * val actor = actorOf(new MyActor).start + **/ def actorOf(factory: => Actor): ActorRef = new LocalActorRef(() => factory) @@ -239,17 +248,57 @@ object Actor extends Logging { * => SHUT DOWN (when 'exit' is invoked) - can't do anything * * + * + * The Actor's API is available in 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]
+ * ...
+ * }
+ *
+ *
+ *
+ * The Actor trait also has a 'log' member field that can be used for logging within the Actor.
+ *
* @author Jonas Bonér
*/
trait Actor extends Logging {
- //Type alias because traits cannot have companion objects...
+ /**
+ * Type alias because traits cannot have companion objects.
+ */
type Receive = Actor.Receive
- /**
+ /*
* For internal use only, functions as the implicit sender references when invoking
- * one of the message send functions (!, !!, !!! and forward).
+ * one of the message send functions (!, !! and !!!).
*/
- implicit val optionSelf: Option[ActorRef] = {
+ implicit val optionSelf: Option[ActorRef] = {
val ref = Actor.actorRefInCreation.value
Actor.actorRefInCreation.value = None
if (ref.isEmpty) throw new ActorInitializationException(
@@ -258,10 +307,15 @@ trait Actor extends Logging {
"\n\tYou have to use one of the factory methods in the 'Actor' object to create a new actor." +
"\n\tEither use:" +
"\n\t\t'val actor = Actor.actorOf[MyActor]', or" +
- "\n\t\t'val actor = Actor.actorOf(new MyActor(..))'")
+ "\n\t\t'val actor = Actor.actorOf(new MyActor(..))'" +
+ "\n\t\t'val actor = Actor.actor { case msg => .. } }'")
else ref
}
+ /*
+ * For internal use only, functions as the implicit sender references when invoking
+ * the forward function.
+ */
implicit val someSelf: Some[ActorRef] = optionSelf.asInstanceOf[Some[ActorRef]]
/**
@@ -274,13 +328,12 @@ trait Actor extends Logging {
*/
val self: ActorRef = optionSelf.get
self.id = getClass.getName
- import self._
/**
* User overridable callback/setting.
*
* Partial function implementing the actor logic.
- * To be implemented by subclassing actor.
+ * To be implemented by concrete actor class.
*
* Example code:
*
diff --git a/akka-core/src/main/scala/actor/ActorRef.scala b/akka-core/src/main/scala/actor/ActorRef.scala
index db2d0ed030..5a5f08adc7 100644
--- a/akka-core/src/main/scala/actor/ActorRef.scala
+++ b/akka-core/src/main/scala/actor/ActorRef.scala
@@ -26,6 +26,7 @@ import java.util.concurrent.locks.ReentrantLock
import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.ConcurrentHashMap
import java.util.{Map => JMap}
+import java.lang.reflect.Field
/**
* The ActorRef object can be used to deserialize ActorRef instances from of its binary representation
@@ -593,7 +594,11 @@ sealed class LocalActorRef private[akka](
@volatile private var isInInitialization = false
@volatile private var runActorInitialization = false
-
+
+ // Needed to be able to null out the 'val self: ActorRef' member variables to make the Actor
+ // instance eligeble for garbage collection
+ private val actorSelfFields = findActorSelfField(actor.getClass)
+
if (runActorInitialization) initializeActorInstance
/**
@@ -720,6 +725,7 @@ sealed class LocalActorRef private[akka](
remoteAddress.foreach(address => RemoteClient.unregister(
address.getHostName, address.getPort, uuid))
RemoteNode.unregister(this)
+ nullOutActorRefReferencesFor(actorInstance.get)
} else if (isBeingRestarted) throw new ActorKilledException("Actor [" + toString + "] is being restarted.")
}
@@ -1082,6 +1088,7 @@ sealed class LocalActorRef private[akka](
Actor.log.debug("Restarting linked actors for actor [%s].", id)
Actor.log.debug("Invoking 'preRestart' for failed actor instance [%s].", id)
failedActor.preRestart(reason)
+ nullOutActorRefReferencesFor(failedActor)
val freshActor = newActor
freshActor.synchronized {
freshActor.init
@@ -1137,7 +1144,30 @@ sealed class LocalActorRef private[akka](
protected[akka] def linkedActorsAsList: List[ActorRef] =
linkedActors.values.toArray.toList.asInstanceOf[List[ActorRef]]
-
+
+ private def nullOutActorRefReferencesFor(actor: Actor) = {
+ actorSelfFields._1.set(actor, null)
+ actorSelfFields._2.set(actor, null)
+ actorSelfFields._3.set(actor, null)
+ }
+
+ private def findActorSelfField(clazz: Class[_]): Tuple3[Field, Field, Field] = {
+ try {
+ val selfField = clazz.getDeclaredField("self")
+ val optionSelfField = clazz.getDeclaredField("optionSelf")
+ val someSelfField = clazz.getDeclaredField("someSelf")
+ selfField.setAccessible(true)
+ optionSelfField.setAccessible(true)
+ someSelfField.setAccessible(true)
+ (selfField, optionSelfField, someSelfField)
+ } catch {
+ case e: NoSuchFieldException =>
+ val parent = clazz.getSuperclass
+ if (parent != null) findActorSelfField(parent)
+ else throw new IllegalStateException(toString + " is not an Actor since it have not mixed in the 'Actor' trait")
+ }
+ }
+
private def initializeActorInstance = if (!isRunning) {
dispatcher.register(this)
dispatcher.start