diff --git a/akka-actor/src/main/scala/actor/Actor.scala b/akka-actor/src/main/scala/actor/Actor.scala index d232ca2a77..3f8e8e9d34 100644 --- a/akka-actor/src/main/scala/actor/Actor.scala +++ b/akka-actor/src/main/scala/actor/Actor.scala @@ -159,7 +159,7 @@ object Actor extends Logging { */ def actor(body: Receive): ActorRef = actorOf(new Actor() { - self.lifeCycle = Some(LifeCycle(Permanent)) + self.lifeCycle = Permanent def receive: Receive = body }).start @@ -181,7 +181,7 @@ object Actor extends Logging { */ def transactor(body: Receive): ActorRef = actorOf(new Transactor() { - self.lifeCycle = Some(LifeCycle(Permanent)) + self.lifeCycle = Permanent def receive: Receive = body }).start @@ -201,7 +201,7 @@ object Actor extends Logging { */ def temporaryActor(body: Receive): ActorRef = actorOf(new Actor() { - self.lifeCycle = Some(LifeCycle(Temporary)) + self.lifeCycle = Temporary def receive = body }).start @@ -226,7 +226,7 @@ object Actor extends Logging { def handler[A](body: => Unit) = new { def receive(handler: Receive) = actorOf(new Actor() { - self.lifeCycle = Some(LifeCycle(Permanent)) + self.lifeCycle = Permanent body def receive = handler }).start @@ -444,7 +444,6 @@ trait Actor extends Logging { */ def become(behavior: Option[Receive]) { self.hotswap = behavior - self.checkReceiveTimeout // FIXME : how to reschedule receivetimeout on hotswap? } /** Akka Java API diff --git a/akka-actor/src/main/scala/actor/ActorRef.scala b/akka-actor/src/main/scala/actor/ActorRef.scala index 0ec35ab9b4..4382d78d5c 100644 --- a/akka-actor/src/main/scala/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/actor/ActorRef.scala @@ -6,11 +6,10 @@ package se.scalablesolutions.akka.actor import se.scalablesolutions.akka.dispatch._ import se.scalablesolutions.akka.config.Config._ -import se.scalablesolutions.akka.config.{AllForOneStrategy, OneForOneStrategy, FaultHandlingStrategy} import se.scalablesolutions.akka.config.ScalaConfig._ import se.scalablesolutions.akka.stm.global._ import se.scalablesolutions.akka.stm.TransactionManagement._ -import se.scalablesolutions.akka.stm.{TransactionManagement, TransactionSetAbortedException} +import se.scalablesolutions.akka.stm.{ TransactionManagement, TransactionSetAbortedException } import se.scalablesolutions.akka.AkkaException import se.scalablesolutions.akka.util._ import ReflectiveAccess._ @@ -22,16 +21,16 @@ import org.multiverse.api.exceptions.DeadTransactionException import java.net.InetSocketAddress import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.atomic.AtomicReference -import java.util.concurrent.{ScheduledFuture, ConcurrentHashMap, TimeUnit} -import java.util.{Map => JMap} +import java.util.concurrent.{ ScheduledFuture, ConcurrentHashMap, TimeUnit } +import java.util.{ Map => JMap } import java.lang.reflect.Field import scala.reflect.BeanProperty - +import se.scalablesolutions.akka.config.{NoFaultHandlingStrategy, AllForOneStrategy, OneForOneStrategy, FaultHandlingStrategy} object ActorRefStatus { - /** LifeCycles for ActorRefs - */ + /** LifeCycles for ActorRefs + */ private[akka] sealed trait StatusType object UNSTARTED extends StatusType object RUNNING extends StatusType @@ -71,17 +70,17 @@ object ActorRefStatus { * * @author Jonas Bonér */ -trait ActorRef extends - ActorRefShared with - TransactionManagement with - Logging with - java.lang.Comparable[ActorRef] { scalaRef: ScalaActorRef => +trait ActorRef extends ActorRefShared with TransactionManagement with Logging with java.lang.Comparable[ActorRef] { scalaRef: ScalaActorRef => // Only mutable for RemoteServer in order to maintain identity across nodes - @volatile protected[akka] var _uuid = newUuid - @volatile protected[this] var _status: ActorRefStatus.StatusType = ActorRefStatus.UNSTARTED - @volatile protected[akka] var _homeAddress = new InetSocketAddress(RemoteServerModule.HOSTNAME, RemoteServerModule.PORT) - @volatile protected[akka] var _futureTimeout: Option[ScheduledFuture[AnyRef]] = None + @volatile + protected[akka] var _uuid = newUuid + @volatile + protected[this] var _status: ActorRefStatus.StatusType = ActorRefStatus.UNSTARTED + @volatile + protected[akka] var _homeAddress = new InetSocketAddress(RemoteServerModule.HOSTNAME, RemoteServerModule.PORT) + @volatile + protected[akka] var _futureTimeout: Option[ScheduledFuture[AnyRef]] = None protected[akka] val guard = new ReentrantGuard /** @@ -94,7 +93,9 @@ trait ActorRef extends * that you can use a custom name to be able to retrieve the "correct" persisted state * upon restart, remote restart etc. */ - @BeanProperty @volatile var id: String = _uuid.toString + @BeanProperty + @volatile + var id: String = _uuid.toString /** * User overridable callback/setting. @@ -102,7 +103,9 @@ trait ActorRef extends * Defines the default timeout for '!!' and '!!!' invocations, * e.g. the timeout for the future returned by the call to '!!' and '!!!'. */ - @BeanProperty @volatile var timeout: Long = Actor.TIMEOUT + @BeanProperty + @volatile + var timeout: Long = Actor.TIMEOUT /** * User overridable callback/setting. @@ -110,7 +113,8 @@ trait ActorRef extends * Defines the default timeout for an initial receive invocation. * When specified, the receive function should be able to handle a 'ReceiveTimeout' message. */ - @volatile var receiveTimeout: Option[Long] = None + @volatile + var receiveTimeout: Option[Long] = None /** * Akka Java API @@ -122,48 +126,22 @@ trait ActorRef extends /** * Akka Java API - * Set 'trapExit' to the list of exception classes that the actor should be able to trap - * from the actor it is supervising. When the supervising actor throws these exceptions - * then they will trigger a restart. - *
- * - * Trap all exceptions: - *
- * getContext().setTrapExit(new Class[]{Throwable.class});
- *
- *
- * Trap specific exceptions only:
- *
- * getContext().setTrapExit(new Class[]{MyApplicationException.class, MyApplicationError.class});
- *
- */
- def setTrapExit(exceptions: Array[Class[_ <: Throwable]]) = trapExit = exceptions.toList
- def getTrapExit(): Array[Class[_ <: Throwable]] = trapExit.toArray
-
- /**
- * Akka Java API
- * If 'trapExit' is set for the actor to act as supervisor, then a 'faultHandler' must be defined.
+ * A faultHandler defines what should be done when a linked actor signals an error.
*
* Can be one of:
*
- * getContext().setFaultHandler(new AllForOneStrategy(maxNrOfRetries, withinTimeRange));
+ * getContext().setFaultHandler(new AllForOneStrategy(new Class[]{Throwable.class},maxNrOfRetries, withinTimeRange));
*
* Or:
*
- * getContext().setFaultHandler(new OneForOneStrategy(maxNrOfRetries, withinTimeRange));
+ * getContext().setFaultHandler(new OneForOneStrategy(new Class[]{Throwable.class},maxNrOfRetries, withinTimeRange));
*
*/
- def setFaultHandler(handler: FaultHandlingStrategy) = this.faultHandler = Some(handler)
- def getFaultHandler(): Option[FaultHandlingStrategy] = faultHandler
+ def setFaultHandler(handler: FaultHandlingStrategy)
+ def getFaultHandler(): FaultHandlingStrategy
- /**
- * Defines the life-cycle for a supervised actor.
- */
- def setLifeCycle(lifeCycle: LifeCycle) = this.lifeCycle = Some(lifeCycle)
- def getLifeCycle(): Option[LifeCycle] = lifeCycle
-
-
- @volatile private[akka] var _dispatcher: MessageDispatcher = Dispatchers.defaultGlobalDispatcher
+ @volatile
+ private[akka] var _dispatcher: MessageDispatcher = Dispatchers.defaultGlobalDispatcher
/**
* Akka Java API
@@ -180,11 +158,11 @@ trait ActorRef extends
def setDispatcher(dispatcher: MessageDispatcher) = this.dispatcher = dispatcher
def getDispatcher(): MessageDispatcher = dispatcher
-
/**
* Holds the hot swapped partial function.
*/
- @volatile protected[akka] var hotswap: Option[PartialFunction[Any, Unit]] = None // FIXME: _hotswap should be a stack
+ @volatile
+ protected[akka] var hotswap: Option[PartialFunction[Any, Unit]] = None // FIXME: _hotswap should be a stack
/**
* User overridable callback/setting.
@@ -192,22 +170,26 @@ trait ActorRef extends
* Set to true if messages should have REQUIRES_NEW semantics, e.g. a new transaction should
* start if there is no one running, else it joins the existing transaction.
*/
- @volatile protected[akka] var isTransactor = false
+ @volatile
+ protected[akka] var isTransactor = false
/**
* Configuration for TransactionFactory. User overridable.
*/
- @volatile protected[akka] var _transactionConfig: TransactionConfig = DefaultGlobalTransactionConfig
+ @volatile
+ protected[akka] var _transactionConfig: TransactionConfig = DefaultGlobalTransactionConfig
/**
* TransactionFactory to be used for atomic when isTransactor. Configuration is overridable.
*/
- @volatile private[akka] var _transactionFactory: Option[TransactionFactory] = None
+ @volatile
+ private[akka] var _transactionFactory: Option[TransactionFactory] = None
/**
* This is a reference to the message currently being processed by the actor
*/
- @volatile protected[akka] var currentMessage: MessageInvocation = null
+ @volatile
+ protected[akka] var currentMessage: MessageInvocation = null
/**
* Comparison only takes uuid into account.
@@ -276,7 +258,7 @@ trait ActorRef extends
*
*
*/
- def sendOneWay(message: AnyRef): Unit = sendOneWay(message,null)
+ def sendOneWay(message: AnyRef): Unit = sendOneWay(message, null)
/**
* Akka Java API
@@ -296,14 +278,14 @@ trait ActorRef extends
* @see sendRequestReply(message: AnyRef, timeout: Long, sender: ActorRef)
* Uses the defualt timeout of the Actor (setTimeout()) and omits the sender reference
*/
- def sendRequestReply(message: AnyRef): AnyRef = sendRequestReply(message,timeout,null)
+ def sendRequestReply(message: AnyRef): AnyRef = sendRequestReply(message, timeout, null)
/**
* Akka Java API
* @see sendRequestReply(message: AnyRef, timeout: Long, sender: ActorRef)
* Uses the defualt timeout of the Actor (setTimeout())
*/
- def sendRequestReply(message: AnyRef, sender: ActorRef): AnyRef = sendRequestReply(message,timeout,sender)
+ def sendRequestReply(message: AnyRef, sender: ActorRef): AnyRef = sendRequestReply(message, timeout, sender)
/**
* Akka Java API
@@ -320,13 +302,13 @@ trait ActorRef extends
* to send a reply message to the original sender. If not then the sender will block until the timeout expires.
*/
def sendRequestReply(message: AnyRef, timeout: Long, sender: ActorRef): AnyRef = {
- !!(message,timeout)(Option(sender)).getOrElse(throw new ActorTimeoutException(
+ !!(message, timeout)(Option(sender)).getOrElse(throw new ActorTimeoutException(
"Message [" + message +
"]\n\tsent to [" + actorClassName +
- "]\n\tfrom [" + (if(sender ne null) sender.actorClassName else "nowhere") +
+ "]\n\tfrom [" + (if (sender ne null) sender.actorClassName else "nowhere") +
"]\n\twith timeout [" + timeout +
"]\n\ttimed out."))
- .asInstanceOf[AnyRef]
+ .asInstanceOf[AnyRef]
}
/**
@@ -334,14 +316,14 @@ trait ActorRef extends
* @see sendRequestReplyFuture(message: AnyRef, sender: ActorRef): Future[_]
* Uses the Actors default timeout (setTimeout()) and omits the sender
*/
- def sendRequestReplyFuture(message: AnyRef): Future[_] = sendRequestReplyFuture(message,timeout,null)
+ def sendRequestReplyFuture(message: AnyRef): Future[_] = sendRequestReplyFuture(message, timeout, null)
/**
* Akka Java API
* @see sendRequestReplyFuture(message: AnyRef, sender: ActorRef): Future[_]
* Uses the Actors default timeout (setTimeout())
*/
- def sendRequestReplyFuture(message: AnyRef, sender: ActorRef): Future[_] = sendRequestReplyFuture(message,timeout,sender)
+ def sendRequestReplyFuture(message: AnyRef, sender: ActorRef): Future[_] = sendRequestReplyFuture(message, timeout, sender)
/**
* Akka Java API
@@ -354,16 +336,15 @@ trait ActorRef extends
* If you are sending messages using sendRequestReplyFuture then you have to use getContext().reply(..)
* to send a reply message to the original sender. If not then the sender will block until the timeout expires.
*/
- def sendRequestReplyFuture(message: AnyRef, timeout: Long, sender: ActorRef): Future[_] = !!!(message,timeout)(Option(sender))
+ def sendRequestReplyFuture(message: AnyRef, timeout: Long, sender: ActorRef): Future[_] = !!!(message, timeout)(Option(sender))
/**
* Akka Java API
* Forwards the message specified to this actor and preserves the original sender of the message
*/
def forward(message: AnyRef, sender: ActorRef): Unit =
- if (sender eq null) throw new IllegalArgumentException("The 'sender' argument to 'forward' can't be null")
- else forward(message)(Some(sender))
-
+ if (sender eq null) throw new IllegalArgumentException("The 'sender' argument to 'forward' can't be null")
+ else forward(message)(Some(sender))
/**
* Akka Java API
@@ -394,7 +375,6 @@ trait ActorRef extends
*/
def getActorClass(): Class[_ <: Actor] = actorClass
-
/**
* Returns the class name for the Actor instance that is managed by the ActorRef.
*/
@@ -443,7 +423,6 @@ trait ActorRef extends
*/
def setTransactionConfig(config: TransactionConfig): Unit = transactionConfig = config
-
/**
* Get the transaction configuration for this actor.
*/
@@ -455,7 +434,6 @@ trait ActorRef extends
*/
def getTransactionConfig(): TransactionConfig = transactionConfig
-
/**
* Returns the home address and port for this actor.
*/
@@ -477,8 +455,7 @@ trait ActorRef extends
* Akka Java API
* Set the home address and port for this actor.
*/
- def setHomeAddress(hostname: String, port: Int): Unit = homeAddress = (hostname,port)
-
+ def setHomeAddress(hostname: String, port: Int): Unit = homeAddress = (hostname, port)
/**
* Set the home address and port for this actor.
@@ -491,7 +468,6 @@ trait ActorRef extends
*/
def setHomeAddress(address: InetSocketAddress): Unit = homeAddress = address
-
/**
* Returns the remote address for the actor, if any, else None.
*/
@@ -504,7 +480,6 @@ trait ActorRef extends
*/
def getRemoteAddress(): Option[InetSocketAddress] = remoteAddress
-
/**
* Starts up the actor and its message queue.
*/
@@ -525,7 +500,7 @@ trait ActorRef extends
* Links an other actor to this actor. Links are unidirectional and means that a the linking actor will
* receive a notification if the linked actor has crashed.
*
- * If the 'trapExit' member field has been set to at contain at least one exception class then it will
+ * If the 'trapExit' member field of the 'faultHandler' has been set to at contain at least one exception class then it will
* 'trap' these exceptions and automatically restart the linked actors according to the restart strategy
* defined by the 'faultHandler'.
*/
@@ -567,7 +542,7 @@ trait ActorRef extends
*/
def spawnLink(clazz: Class[_ <: Actor]): ActorRef
- /**
+ /**
* Atomically create (from actor class), make it remote, link and start an actor.
*
* To be invoked from within the actor itself.
@@ -601,10 +576,10 @@ trait ActorRef extends
protected[akka] def postMessageToMailbox(message: Any, senderOption: Option[ActorRef]): Unit
protected[akka] def postMessageToMailboxAndCreateFutureResultWithTimeout[T](
- message: Any,
- timeout: Long,
- senderOption: Option[ActorRef],
- senderFuture: Option[CompletableFuture[T]]): CompletableFuture[T]
+ message: Any,
+ timeout: Long,
+ senderOption: Option[ActorRef],
+ senderFuture: Option[CompletableFuture[T]]): CompletableFuture[T]
protected[akka] def actorInstance: AtomicReference[Actor]
@@ -625,12 +600,9 @@ trait ActorRef extends
protected[akka] def linkedActors: JMap[Uuid, ActorRef]
- protected[akka] def linkedActorsAsList: List[ActorRef]
-
override def hashCode: Int = HashCode.hash(HashCode.SEED, uuid)
override def equals(that: Any): Boolean = {
- that != null &&
that.isInstanceOf[ActorRef] &&
that.asInstanceOf[ActorRef].uuid == uuid
}
@@ -639,14 +611,14 @@ trait ActorRef extends
protected[akka] def checkReceiveTimeout = {
cancelReceiveTimeout
- receiveTimeout.foreach { time =>
+ if (receiveTimeout.isDefined && dispatcher.mailboxSize(this) <= 0) { //Only reschedule if desired and there are currently no more messages to be processed
log.debug("Scheduling timeout for %s", this)
- _futureTimeout = Some(Scheduler.scheduleOnce(this, ReceiveTimeout, time, TimeUnit.MILLISECONDS))
+ _futureTimeout = Some(Scheduler.scheduleOnce(this, ReceiveTimeout, receiveTimeout.get, TimeUnit.MILLISECONDS))
}
}
protected[akka] def cancelReceiveTimeout = {
- if(_futureTimeout.isDefined) {
+ if (_futureTimeout.isDefined) {
_futureTimeout.get.cancel(true)
_futureTimeout = None
log.debug("Timeout canceled for %s", this)
@@ -659,20 +631,22 @@ trait ActorRef extends
*
* @author Jonas Bonér
*/
-class LocalActorRef private[akka](
+class LocalActorRef private[akka] (
private[this] var actorFactory: Either[Option[Class[_ <: Actor]], Option[() => Actor]] = Left(None))
extends ActorRef with ScalaActorRef {
- @volatile private[akka] var _remoteAddress: Option[InetSocketAddress] = None // only mutable to maintain identity across nodes
- @volatile private[akka] var _linkedActors: Option[ConcurrentHashMap[Uuid, ActorRef]] = None
- @volatile private[akka] var _supervisor: Option[ActorRef] = None
- @volatile private var isInInitialization = false
- @volatile private var runActorInitialization = false
- @volatile private var isDeserialized = false
- @volatile private var loader: Option[ClassLoader] = None
- @volatile private var maxNrOfRetriesCount: Int = 0
- @volatile private var restartsWithinTimeRangeTimestamp: Long = 0L
- @volatile private var _mailbox: AnyRef = _
+ @volatile
+ private[akka] var _remoteAddress: Option[InetSocketAddress] = None // only mutable to maintain identity across nodes
+ @volatile
+ private[akka] lazy val _linkedActors = new ConcurrentHashMap[Uuid, ActorRef]
+ @volatile
+ private[akka] var _supervisor: Option[ActorRef] = None
+ @volatile
+ private var maxNrOfRetriesCount: Int = 0
+ @volatile
+ private var restartsWithinTimeRangeTimestamp: Long = 0L
+ @volatile
+ private var _mailbox: AnyRef = _
protected[akka] val actorInstance = guard.withGuard { new AtomicReference[Actor](newActor) }
@@ -680,42 +654,39 @@ class LocalActorRef private[akka](
// instance elegible for garbage collection
private val actorSelfFields = findActorSelfField(actor.getClass)
- if (runActorInitialization && !isDeserialized) initializeActorInstance
+ //If it was started inside "newActor", initialize it
+ if (isRunning) initializeActorInstance
private[akka] def this(clazz: Class[_ <: Actor]) = this(Left(Some(clazz)))
- private[akka] def this(factory: () => Actor) = this(Right(Some(factory)))
+ private[akka] def this(factory: () => Actor) = this(Right(Some(factory)))
// used only for deserialization
private[akka] def this(__uuid: Uuid,
- __id: String,
- __hostname: String,
- __port: Int,
- __isTransactor: Boolean,
- __timeout: Long,
- __receiveTimeout: Option[Long],
- __lifeCycle: Option[LifeCycle],
- __supervisor: Option[ActorRef],
- __hotswap: Option[PartialFunction[Any, Unit]],
- __loader: ClassLoader,
- __factory: () => Actor) = {
- this(__factory)
- loader = Some(__loader)
- isDeserialized = true
- _uuid = __uuid
- id = __id
- homeAddress = (__hostname, __port)
- isTransactor = __isTransactor
- timeout = __timeout
- receiveTimeout = __receiveTimeout
- lifeCycle = __lifeCycle
- _supervisor = __supervisor
- hotswap = __hotswap
- actorSelfFields._1.set(actor, this)
- actorSelfFields._2.set(actor, Some(this))
- start
- checkReceiveTimeout
- ActorRegistry.register(this)
- }
+ __id: String,
+ __hostname: String,
+ __port: Int,
+ __isTransactor: Boolean,
+ __timeout: Long,
+ __receiveTimeout: Option[Long],
+ __lifeCycle: LifeCycle,
+ __supervisor: Option[ActorRef],
+ __hotswap: Option[PartialFunction[Any, Unit]],
+ __factory: () => Actor) = {
+ this(__factory)
+ _uuid = __uuid
+ id = __id
+ homeAddress = (__hostname, __port)
+ isTransactor = __isTransactor
+ timeout = __timeout
+ receiveTimeout = __receiveTimeout
+ lifeCycle = __lifeCycle
+ _supervisor = __supervisor
+ hotswap = __hotswap
+ actorSelfFields._1.set(actor, this)
+ actorSelfFields._2.set(actor, Some(this))
+ start
+ ActorRegistry.register(this)
+ }
// ========= PUBLIC FUNCTIONS =========
@@ -736,7 +707,7 @@ class LocalActorRef private[akka](
if (!isBeingRestarted) {
if (!isRunning) _dispatcher = md
else throw new ActorInitializationException(
- "Can not swap dispatcher for " + toString + " after it has been started")
+ "Can not swap dispatcher for " + toString + " after it has been started")
}
}
@@ -817,8 +788,11 @@ class LocalActorRef private[akka](
_transactionFactory = Some(TransactionFactory(_transactionConfig, id))
}
_status = ActorRefStatus.RUNNING
- if (!isInInitialization) initializeActorInstance
- else runActorInitialization = true
+
+ //If actorRefInCreation is empty, we're outside creation of the actor, and so we can initialize the actor instance.
+ if (Actor.actorRefInCreation.value.isEmpty) initializeActorInstance
+
+ checkReceiveTimeout //Schedule the initial Receive timeout
}
this
}
@@ -828,6 +802,7 @@ class LocalActorRef private[akka](
*/
def stop() = guard.withGuard {
if (isRunning) {
+ receiveTimeout = None
cancelReceiveTimeout
dispatcher.unregister(this)
_transactionFactory = None
@@ -835,8 +810,8 @@ class LocalActorRef private[akka](
actor.postStop
ActorRegistry.unregister(this)
if (isRemotingEnabled) {
- if(remoteAddress.isDefined)
- RemoteClientModule.unregister(remoteAddress.get, uuid)
+ if (remoteAddress.isDefined)
+ RemoteClientModule.unregister(remoteAddress.get, uuid)
RemoteServerModule.unregister(this)
}
nullOutActorRefReferencesFor(actorInstance.get)
@@ -847,7 +822,7 @@ class LocalActorRef private[akka](
* Links an other actor to this actor. Links are unidirectional and means that a the linking actor will
* receive a notification if the linked actor has crashed.
*
- * If the 'trapExit' member field has been set to at contain at least one exception class then it will
+ * If the 'trapExit' member field of the 'faultHandler' has been set to at contain at least one exception class then it will
* 'trap' these exceptions and automatically restart the linked actors according to the restart strategy
* defined by the 'faultHandler'.
*
@@ -879,7 +854,7 @@ class LocalActorRef private[akka](
*
* To be invoked from within the actor itself.
*/
- def startLink(actorRef: ActorRef):Unit = guard.withGuard {
+ def startLink(actorRef: ActorRef): Unit = guard.withGuard {
try {
link(actorRef)
} finally {
@@ -961,14 +936,17 @@ class LocalActorRef private[akka](
*/
def mailbox: AnyRef = _mailbox
- protected[akka] def mailbox_=(value: AnyRef):AnyRef = { _mailbox = value; value }
+ protected[akka] def mailbox_=(value: AnyRef): AnyRef = { _mailbox = value; value }
/**
* Shuts down and removes all linked actors.
*/
- def shutdownLinkedActors(): Unit = {
- linkedActorsAsList.foreach(_.stop)
- linkedActors.clear
+ def shutdownLinkedActors() {
+ val i = linkedActors.values.iterator
+ while(i.hasNext) {
+ i.next.stop
+ i.remove
+ }
}
/**
@@ -993,10 +971,10 @@ class LocalActorRef private[akka](
}
protected[akka] def postMessageToMailboxAndCreateFutureResultWithTimeout[T](
- message: Any,
- timeout: Long,
- senderOption: Option[ActorRef],
- senderFuture: Option[CompletableFuture[T]]): CompletableFuture[T] = {
+ message: Any,
+ timeout: Long,
+ senderOption: Option[ActorRef],
+ senderFuture: Option[CompletableFuture[T]]): CompletableFuture[T] = {
joinTransaction(message)
if (remoteAddress.isDefined && isRemotingEnabled) {
@@ -1006,7 +984,7 @@ class LocalActorRef private[akka](
else throw new IllegalActorStateException("Expected a future from remote call to actor " + toString)
} else {
val future = if (senderFuture.isDefined) senderFuture.get
- else new DefaultCompletableFuture[T](timeout)
+ else new DefaultCompletableFuture[T](timeout)
val invocation = new MessageInvocation(
this, message, senderOption, Some(future.asInstanceOf[CompletableFuture[Any]]), transactionSet.get)
dispatcher dispatch invocation
@@ -1028,41 +1006,41 @@ class LocalActorRef private[akka](
case e =>
Actor.log.error(e, "Could not invoke actor [%s]", this)
throw e
- } finally {
+ }
+ finally {
currentMessage = null //TODO: Don't reset this, we might want to resend the message
}
}
}
protected[akka] def handleTrapExit(dead: ActorRef, reason: Throwable): Unit = {
- if (trapExit.exists(_.isAssignableFrom(reason.getClass))) {
+ if (faultHandler.trapExit.exists(_.isAssignableFrom(reason.getClass))) {
faultHandler match {
- case Some(AllForOneStrategy(maxNrOfRetries, withinTimeRange)) =>
+ case AllForOneStrategy(_,maxNrOfRetries, withinTimeRange) =>
restartLinkedActors(reason, maxNrOfRetries, withinTimeRange)
- case Some(OneForOneStrategy(maxNrOfRetries, withinTimeRange)) =>
+ case OneForOneStrategy(_,maxNrOfRetries, withinTimeRange) =>
dead.restart(reason, maxNrOfRetries, withinTimeRange)
- case None => throw new IllegalActorStateException(
- "No 'faultHandler' defined for an actor with the 'trapExit' member field defined " +
- "\n\tto non-empty list of exception classes - can't proceed " + toString)
+ case NoFaultHandlingStrategy =>
+ notifySupervisorWithMessage(Exit(this, reason)) //This shouldn't happen
}
} else {
- notifySupervisorWithMessage(Exit(this, reason)) // if 'trapExit' is not defined then pass the Exit on
+ notifySupervisorWithMessage(Exit(this, reason)) // if 'trapExit' isn't triggered then pass the Exit on
}
}
protected[akka] def restart(reason: Throwable, maxNrOfRetries: Option[Int], withinTimeRange: Option[Int]): Unit = {
if (maxNrOfRetriesCount == 0) restartsWithinTimeRangeTimestamp = System.currentTimeMillis // first time around
-
+
val tooManyRestarts = if (maxNrOfRetries.isDefined) {
- maxNrOfRetriesCount += 1
- maxNrOfRetriesCount > maxNrOfRetries.get
- } else false
+ maxNrOfRetriesCount += 1
+ maxNrOfRetriesCount > maxNrOfRetries.get
+ } else false
val restartingHasExpired = if (withinTimeRange.isDefined)
- (System.currentTimeMillis - restartsWithinTimeRangeTimestamp) > withinTimeRange.get
- else false
+ (System.currentTimeMillis - restartsWithinTimeRangeTimestamp) > withinTimeRange.get
+ else false
if (tooManyRestarts || restartingHasExpired) {
val notification = MaximumNumberOfRestartsWithinTimeRangeReached(this, maxNrOfRetries, withinTimeRange, reason)
@@ -1086,7 +1064,7 @@ class LocalActorRef private[akka](
val failedActor = actorInstance.get
guard.withGuard {
lifeCycle match {
- case Some(LifeCycle(Temporary)) => shutDownTemporaryActor(this)
+ case Temporary => shutDownTemporaryActor(this)
case _ =>
// either permanent or none where default is permanent
Actor.log.info("Restarting actor [%s] configured as PERMANENT.", id)
@@ -1095,8 +1073,8 @@ class LocalActorRef private[akka](
Actor.log.debug("Invoking 'preRestart' for failed actor instance [%s].", id)
if (isProxyableDispatcher(failedActor)) restartProxyableDispatcher(failedActor, reason)
- else restartActor(failedActor, reason)
-
+ else restartActor(failedActor, reason)
+
_status = ActorRefStatus.RUNNING
}
}
@@ -1104,10 +1082,11 @@ class LocalActorRef private[akka](
}
protected[akka] def restartLinkedActors(reason: Throwable, maxNrOfRetries: Option[Int], withinTimeRange: Option[Int]) = {
- linkedActorsAsList.foreach { actorRef =>
+ import scala.collection.JavaConversions._
+ linkedActors.values foreach { actorRef =>
actorRef.lifeCycle match {
// either permanent or none where default is permanent
- case Some(LifeCycle(Temporary)) => shutDownTemporaryActor(actorRef)
+ case Temporary => shutDownTemporaryActor(actorRef)
case _ => actorRef.restart(reason, maxNrOfRetries, withinTimeRange)
}
}
@@ -1121,16 +1100,7 @@ class LocalActorRef private[akka](
} else None
}
- protected[akka] def linkedActors: JMap[Uuid, ActorRef] = guard.withGuard {
- if (_linkedActors.isEmpty) {
- val actors = new ConcurrentHashMap[Uuid, ActorRef]
- _linkedActors = Some(actors)
- actors
- } else _linkedActors.get
- }
-
- protected[akka] def linkedActorsAsList: List[ActorRef] =
- linkedActors.values.toArray.toList.asInstanceOf[List[ActorRef]]
+ protected[akka] def linkedActors: JMap[Uuid, ActorRef] = _linkedActors
// ========= PRIVATE FUNCTIONS =========
@@ -1156,27 +1126,25 @@ class LocalActorRef private[akka](
private def spawnButDoNotStart(clazz: Class[_ <: Actor]): ActorRef = Actor.actorOf(clazz.newInstance)
private[this] def newActor: Actor = {
- Actor.actorRefInCreation.withValue(Some(this)){
- isInInitialization = true
- val actor = actorFactory match {
- case Left(Some(clazz)) =>
- import ReflectiveAccess.{createInstance,noParams,noArgs}
- createInstance(clazz.asInstanceOf[Class[_]],noParams,noArgs).
- getOrElse(throw new ActorInitializationException(
- "Could not instantiate Actor" +
- "\nMake sure Actor is NOT defined inside a class/trait," +
- "\nif so put it outside the class/trait, f.e. in a companion object," +
- "\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'."))
- case Right(Some(factory)) =>
- factory()
- case _ =>
- throw new ActorInitializationException(
- "Can't create Actor, no Actor class or factory function in scope")
- }
- if (actor eq null) throw new ActorInitializationException(
- "Actor instance passed to ActorRef can not be 'null'")
- isInInitialization = false
- actor
+ Actor.actorRefInCreation.withValue(Some(this)) {
+ val actor = actorFactory match {
+ case Left(Some(clazz)) =>
+ import ReflectiveAccess.{ createInstance, noParams, noArgs }
+ createInstance(clazz.asInstanceOf[Class[_]], noParams, noArgs).
+ getOrElse(throw new ActorInitializationException(
+ "Could not instantiate Actor" +
+ "\nMake sure Actor is NOT defined inside a class/trait," +
+ "\nif so put it outside the class/trait, f.e. in a companion object," +
+ "\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'."))
+ case Right(Some(factory)) =>
+ factory()
+ case _ =>
+ throw new ActorInitializationException(
+ "Can't create Actor, no Actor class or factory function in scope")
+ }
+ if (actor eq null) throw new ActorInitializationException(
+ "Actor instance passed to ActorRef can not be 'null'")
+ actor
}
}
@@ -1188,15 +1156,15 @@ class LocalActorRef private[akka](
createNewTransactionSet
} else oldTxSet
Actor.log.trace("Joining transaction set [" + currentTxSet +
- "];\n\tactor " + toString +
- "\n\twith message [" + message + "]")
+ "];\n\tactor " + toString +
+ "\n\twith message [" + message + "]")
val mtx = ThreadLocalTransaction.getThreadLocalTransaction
if ((mtx eq null) || mtx.getStatus.isDead) currentTxSet.incParties
else currentTxSet.incParties(mtx, 1)
}
private def dispatch[T](messageHandle: MessageInvocation) = {
- Actor.log.trace("Invoking actor with message: %s\n",messageHandle)
+ Actor.log.trace("Invoking actor with message: %s\n", messageHandle)
val message = messageHandle.message //serializeMessage(messageHandle.message)
var topLevelTransaction = false
val txSet: Option[CountDownCommitBarrier] =
@@ -1205,7 +1173,7 @@ class LocalActorRef private[akka](
topLevelTransaction = true // FIXME create a new internal atomic block that can wait for X seconds if top level tx
if (isTransactor) {
Actor.log.trace("Creating a new transaction set (top-level transaction)\n\tfor actor " + toString +
- "\n\twith message " + messageHandle)
+ "\n\twith message " + messageHandle)
Some(createNewTransactionSet)
} else None
}
@@ -1230,9 +1198,11 @@ class LocalActorRef private[akka](
message, topLevelTransaction)
case e: InterruptedException => {} // received message while actor is shutting down, ignore
case e => handleExceptionInDispatch(e, message, topLevelTransaction)
- } finally {
+ }
+ finally {
clearTransaction
if (topLevelTransaction) clearTransactionSet
+ checkReceiveTimeout // Reschedule receive timeout
}
}
@@ -1246,7 +1216,7 @@ class LocalActorRef private[akka](
"All linked actors have died permanently (they were all configured as TEMPORARY)" +
"\n\tshutting down and unlinking supervisor actor as well [%s].",
temporaryActor.id)
- notifySupervisorWithMessage(UnlinkAndStop(this))
+ notifySupervisorWithMessage(UnlinkAndStop(this))
}
}
@@ -1271,7 +1241,7 @@ class LocalActorRef private[akka](
if (supervisor.isDefined) notifySupervisorWithMessage(Exit(this, reason))
else {
lifeCycle match {
- case Some(LifeCycle(Temporary)) => shutDownTemporaryActor(this)
+ case Temporary => shutDownTemporaryActor(this)
case _ =>
}
}
@@ -1281,8 +1251,8 @@ class LocalActorRef private[akka](
// FIXME to fix supervisor restart of remote actor for oneway calls, inject a supervisor proxy that can send notification back to client
_supervisor.foreach { sup =>
if (sup.isShutdown) { // if supervisor is shut down, game over for all linked actors
- shutdownLinkedActors
- stop
+ shutdownLinkedActors
+ stop
} else sup ! notification // else notify supervisor
}
}
@@ -1294,15 +1264,15 @@ class LocalActorRef private[akka](
private def findActorSelfField(clazz: Class[_]): Tuple2[Field, Field] = {
try {
- val selfField = clazz.getDeclaredField("self")
- val someSelfField = clazz.getDeclaredField("someSelf")
+ val selfField = clazz.getDeclaredField("self")
+ val someSelfField = clazz.getDeclaredField("someSelf")
selfField.setAccessible(true)
someSelfField.setAccessible(true)
(selfField, someSelfField)
} catch {
case e: NoSuchFieldException =>
val parent = clazz.getSuperclass
- if (parent != null) findActorSelfField(parent)
+ if (parent ne null) findActorSelfField(parent)
else throw new IllegalActorStateException(
toString + " is not an Actor since it have not mixed in the 'Actor' trait")
}
@@ -1312,12 +1282,10 @@ class LocalActorRef private[akka](
actor.preStart // run actor preStart
Actor.log.trace("[%s] has started", toString)
ActorRegistry.register(this)
- if (id == "N/A") id = actorClass.getName // if no name set, then use default name (class name)
clearTransactionSet // clear transaction set that might have been created if atomic block has been used within the Actor constructor body
- checkReceiveTimeout
}
-/*
+ /*
private def serializeMessage(message: AnyRef): AnyRef = if (Actor.SERIALIZE_MESSAGES) {
if (!message.isInstanceOf[String] &&
!message.isInstanceOf[Byte] &&
@@ -1361,12 +1329,12 @@ object RemoteActorSystemMessage {
*/
private[akka] case class RemoteActorRef private[akka] (
classOrServiceName: String,
- val className: String,
+ val actorClassName: String,
val hostname: String,
val port: Int,
_timeout: Long,
loader: Option[ClassLoader],
- val actorType: ActorType = ActorType.ScalaActor)
+ val actorType: ActorType = ActorType.ScalaActor)
extends ActorRef with ScalaActorRef {
ensureRemotingEnabled
@@ -1375,38 +1343,34 @@ private[akka] case class RemoteActorRef private[akka] (
timeout = _timeout
start
- lazy val remoteClient = RemoteClientModule.clientFor(hostname, port, loader)
def postMessageToMailbox(message: Any, senderOption: Option[ActorRef]): Unit =
RemoteClientModule.send[Any](
message, senderOption, None, remoteAddress.get, timeout, true, this, None, actorType)
def postMessageToMailboxAndCreateFutureResultWithTimeout[T](
- message: Any,
- timeout: Long,
- senderOption: Option[ActorRef],
- senderFuture: Option[CompletableFuture[T]]): CompletableFuture[T] = {
+ message: Any,
+ timeout: Long,
+ senderOption: Option[ActorRef],
+ senderFuture: Option[CompletableFuture[T]]): CompletableFuture[T] = {
val future = RemoteClientModule.send[T](
message, senderOption, senderFuture, remoteAddress.get, timeout, false, this, None, actorType)
if (future.isDefined) future.get
else throw new IllegalActorStateException("Expected a future from remote call to actor " + toString)
}
- def start: ActorRef = {
+ def start: ActorRef = synchronized {
_status = ActorRefStatus.RUNNING
this
}
- def stop: Unit = {
- _status = ActorRefStatus.SHUTDOWN
- postMessageToMailbox(RemoteActorSystemMessage.Stop, None)
+ def stop: Unit = synchronized {
+ if (_status == ActorRefStatus.RUNNING) {
+ _status = ActorRefStatus.SHUTDOWN
+ postMessageToMailbox(RemoteActorSystemMessage.Stop, None)
+ }
}
- /**
- * Returns the class name for the Actor instance that is managed by the ActorRef.
- */
- def actorClassName: String = className
-
protected[akka] def registerSupervisorAsRemoteActor: Option[Uuid] = None
val remoteAddress: Option[InetSocketAddress] = Some(new InetSocketAddress(hostname, port))
@@ -1432,12 +1396,11 @@ private[akka] case class RemoteActorRef private[akka] (
def supervisor: Option[ActorRef] = unsupported
def shutdownLinkedActors: Unit = unsupported
protected[akka] def mailbox: AnyRef = unsupported
- protected[akka] def mailbox_=(value: AnyRef):AnyRef = unsupported
+ protected[akka] def mailbox_=(value: AnyRef): AnyRef = unsupported
protected[akka] def handleTrapExit(dead: ActorRef, reason: Throwable): Unit = unsupported
protected[akka] def restart(reason: Throwable, maxNrOfRetries: Option[Int], withinTimeRange: Option[Int]): Unit = unsupported
protected[akka] def restartLinkedActors(reason: Throwable, maxNrOfRetries: Option[Int], withinTimeRange: Option[Int]): Unit = unsupported
protected[akka] def linkedActors: JMap[Uuid, ActorRef] = unsupported
- protected[akka] def linkedActorsAsList: List[ActorRef] = unsupported
protected[akka] def invoke(messageHandle: MessageInvocation): Unit = unsupported
protected[akka] def remoteAddress_=(addr: Option[InetSocketAddress]): Unit = unsupported
protected[akka] def supervisor_=(sup: Option[ActorRef]): Unit = unsupported
@@ -1474,68 +1437,44 @@ trait ActorRefShared {
*/
trait ScalaActorRef extends ActorRefShared { ref: ActorRef =>
- /**
- * Identifier for actor, does not have to be a unique one. Default is the 'uuid'.
- *
- * This field is used for logging, AspectRegistry.actorsFor(id), identifier for remote
- * actor in RemoteServer etc.But also as the identifier for persistence, which means
- * that you can use a custom name to be able to retrieve the "correct" persisted state
- * upon restart, remote restart etc.
- */
- def id: String
-
- def id_=(id: String): Unit
-
- /**
- * User overridable callback/setting.
+ /**
+ * Identifier for actor, does not have to be a unique one. Default is the 'uuid'.
*
- * Defines the life-cycle for a supervised actor.
+ * This field is used for logging, AspectRegistry.actorsFor(id), identifier for remote
+ * actor in RemoteServer etc.But also as the identifier for persistence, which means
+ * that you can use a custom name to be able to retrieve the "correct" persisted state
+ * upon restart, remote restart etc.
*/
- @volatile var lifeCycle: Option[LifeCycle] = None
-
- /**
- * User overridable callback/setting.
- *
- *
- * Set trapExit to the list of exception classes that the actor should be able to trap
- * from the actor it is supervising. When the supervising actor throws these exceptions
- * then they will trigger a restart.
- *
- *
- * Trap no exceptions:
- * - * trapExit = Nil - *- * - * Trap all exceptions: - *
- * trapExit = List(classOf[Throwable]) - *- * - * Trap specific exceptions only: - *
- * trapExit = List(classOf[MyApplicationException], classOf[MyApplicationError]) - *- */ - @volatile var trapExit: List[Class[_ <: Throwable]] = Nil + def id: String + def id_=(id: String): Unit /** * User overridable callback/setting. * - * If 'trapExit' is set for the actor to act as supervisor, then a faultHandler must be defined. + * Defines the life-cycle for a supervised actor. + */ + @volatile + @BeanProperty + var lifeCycle: LifeCycle = UndefinedLifeCycle + + /** + * User overridable callback/setting. + * + * Don't forget to supply a List of exception types to intercept (trapExit) * * Can be one of: *
- * faultHandler = Some(AllForOneStrategy(maxNrOfRetries, withinTimeRange))
+ * faultHandler = AllForOneStrategy(trapExit = List(classOf[Exception]),maxNrOfRetries, withinTimeRange)
*
* Or:
*
- * faultHandler = Some(OneForOneStrategy(maxNrOfRetries, withinTimeRange))
+ * faultHandler = OneForOneStrategy(trapExit = List(classOf[Exception]),maxNrOfRetries, withinTimeRange)
*
*/
- @volatile var faultHandler: Option[FaultHandlingStrategy] = None
-
+ @volatile
+ @BeanProperty
+ var faultHandler: FaultHandlingStrategy = NoFaultHandlingStrategy
/**
* The reference sender Actor of the last received message.
@@ -1557,7 +1496,6 @@ trait ScalaActorRef extends ActorRefShared { ref: ActorRef =>
else msg.senderFuture
}
-
/**
* Sends a one-way asynchronous message. E.g. fire-and-forget semantics.
*
@@ -1594,7 +1532,7 @@ trait ScalaActorRef extends ActorRefShared { ref: ActorRef =>
if (isRunning) {
val future = postMessageToMailboxAndCreateFutureResultWithTimeout[Any](message, timeout, sender, None)
val isMessageJoinPoint = if (isTypedActorEnabled) TypedActorModule.resolveFutureIfMessageIsJoinPoint(message, future)
- else false
+ else false
try {
future.await
} catch {
@@ -1605,10 +1543,9 @@ trait ScalaActorRef extends ActorRefShared { ref: ActorRef =>
if (future.exception.isDefined) throw future.exception.get
else future.result
} else throw new ActorInitializationException(
- "Actor has not been started, you need to invoke 'actor.start' before using it")
+ "Actor has not been started, you need to invoke 'actor.start' before using it")
}
-
/**
* Sends a message asynchronously returns a future holding the eventual reply message.
*
@@ -1644,7 +1581,7 @@ trait ScalaActorRef extends ActorRefShared { ref: ActorRef =>
*
* Throws an IllegalStateException if unable to determine what to reply to.
*/
- def reply(message: Any) = if(!reply_?(message)) throw new IllegalActorStateException(
+ def reply(message: Any) = if (!reply_?(message)) throw new IllegalActorStateException(
"\n\tNo sender in scope, can't reply. " +
"\n\tYou have probably: " +
"\n\t\t1. Sent a message to an Actor from an instance that is NOT an Actor." +
@@ -1667,12 +1604,27 @@ trait ScalaActorRef extends ActorRefShared { ref: ActorRef =>
} else false
}
-
+ /**
+ * Abstraction for unification of sender and senderFuture for later reply
+ */
+ def channel: Channel[Any] = {
+ if (senderFuture.isDefined) {
+ new Channel[Any] {
+ val future = senderFuture.get
+ def !(msg: Any) = future completeWithResult msg
+ }
+ } else if (sender.isDefined) {
+ new Channel[Any] {
+ val client = sender.get
+ def !(msg: Any) = client ! msg
+ }
+ } else throw new IllegalActorStateException("No channel available")
+ }
/**
* Atomically create (from actor class) and start an actor.
*/
- def spawn[T <: Actor : Manifest]: ActorRef =
+ def spawn[T <: Actor: Manifest]: ActorRef =
spawn(manifest[T].erasure.asInstanceOf[Class[_ <: Actor]])
/**
@@ -1680,10 +1632,9 @@ trait ScalaActorRef extends ActorRefShared { ref: ActorRef =>
*/
def spawnRemote[T <: Actor: Manifest](hostname: String, port: Int): ActorRef = {
ensureRemotingEnabled
- spawnRemote(manifest[T].erasure.asInstanceOf[Class[_ <: Actor]],hostname,port)
+ spawnRemote(manifest[T].erasure.asInstanceOf[Class[_ <: Actor]], hostname, port)
}
-
/**
* Atomically create (from actor class), start and link an actor.
*/
@@ -1693,8 +1644,15 @@ trait ScalaActorRef extends ActorRefShared { ref: ActorRef =>
/**
* Atomically create (from actor class), start, link and make an actor remote.
*/
- def spawnLinkRemote[T <: Actor : Manifest](hostname: String, port: Int): ActorRef = {
+ def spawnLinkRemote[T <: Actor: Manifest](hostname: String, port: Int): ActorRef = {
ensureRemotingEnabled
- spawnLinkRemote(manifest[T].erasure.asInstanceOf[Class[_ <: Actor]],hostname,port)
+ spawnLinkRemote(manifest[T].erasure.asInstanceOf[Class[_ <: Actor]], hostname, port)
}
}
+
+/**
+ * Abstraction for unification of sender and senderFuture for later reply
+ */
+abstract class Channel[T] {
+ def !(msg: T): Unit
+}
diff --git a/akka-actor/src/main/scala/actor/ActorRegistry.scala b/akka-actor/src/main/scala/actor/ActorRegistry.scala
index e425451470..41bff91132 100644
--- a/akka-actor/src/main/scala/actor/ActorRegistry.scala
+++ b/akka-actor/src/main/scala/actor/ActorRegistry.scala
@@ -4,14 +4,16 @@
package se.scalablesolutions.akka.actor
-import scala.collection.mutable.ListBuffer
+import scala.collection.mutable.{ListBuffer, Map}
import scala.reflect.Manifest
import java.util.concurrent.{ConcurrentSkipListSet, ConcurrentHashMap}
import java.util.{Set => JSet}
-import se.scalablesolutions.akka.util.ListenerManagement
import annotation.tailrec
+import se.scalablesolutions.akka.util.ReflectiveAccess._
+import se.scalablesolutions.akka.util.{ReadWriteGuard, Address, ListenerManagement}
+import java.net.InetSocketAddress
/**
* Base trait for ActorRegistry events, allows listen to when an actor is added and removed from the ActorRegistry.
@@ -37,11 +39,18 @@ case class ActorUnregistered(actor: ActorRef) extends ActorRegistryEvent
object ActorRegistry extends ListenerManagement {
private val actorsByUUID = new ConcurrentHashMap[Uuid, ActorRef]
private val actorsById = new Index[String,ActorRef]
+ private val remoteActorSets = Map[Address, RemoteActorSet]()
+ private val guard = new ReadWriteGuard
/**
* Returns all actors in the system.
*/
def actors: Array[ActorRef] = filter(_ => true)
+
+ /**
+ * Returns the number of actors in the system.
+ */
+ def size : Int = actorsByUUID.size
/**
* Invokes a function for all actors.
@@ -109,11 +118,122 @@ object ActorRegistry extends ListenerManagement {
*/
def actorsFor(id: String): Array[ActorRef] = actorsById values id
- /**
+ /**
* Finds the actor that has a specific UUID.
*/
def actorFor(uuid: Uuid): Option[ActorRef] = Option(actorsByUUID get uuid)
+ /**
+ * Returns all typed actors in the system.
+ */
+ def typedActors: Array[AnyRef] = filterTypedActors(_ => true)
+
+ /**
+ * Invokes a function for all typed actors.
+ */
+ def foreachTypedActor(f: (AnyRef) => Unit) = {
+ TypedActorModule.ensureTypedActorEnabled
+ val elements = actorsByUUID.elements
+ while (elements.hasMoreElements) {
+ val proxy = typedActorFor(elements.nextElement)
+ if (proxy.isDefined) {
+ f(proxy.get)
+ }
+ }
+ }
+
+ /**
+ * Invokes the function on all known typed actors until it returns Some
+ * Returns None if the function never returns Some
+ */
+ def findTypedActor[T](f: PartialFunction[AnyRef,T]) : Option[T] = {
+ TypedActorModule.ensureTypedActorEnabled
+ val elements = actorsByUUID.elements
+ while (elements.hasMoreElements) {
+ val proxy = typedActorFor(elements.nextElement)
+ if(proxy.isDefined && (f isDefinedAt proxy))
+ return Some(f(proxy))
+ }
+ None
+ }
+
+ /**
+ * Finds all typed actors that satisfy a predicate.
+ */
+ def filterTypedActors(p: AnyRef => Boolean): Array[AnyRef] = {
+ TypedActorModule.ensureTypedActorEnabled
+ val all = new ListBuffer[AnyRef]
+ val elements = actorsByUUID.elements
+ while (elements.hasMoreElements) {
+ val proxy = typedActorFor(elements.nextElement)
+ if (proxy.isDefined && p(proxy.get)) {
+ all += proxy.get
+ }
+ }
+ all.toArray
+ }
+
+ /**
+ * Finds all typed actors that are subtypes of the class passed in as the Manifest argument.
+ */
+ def typedActorsFor[T <: AnyRef](implicit manifest: Manifest[T]): Array[AnyRef] = {
+ TypedActorModule.ensureTypedActorEnabled
+ typedActorsFor[T](manifest.erasure.asInstanceOf[Class[T]])
+ }
+
+ /**
+ * Finds any typed actor that matches T.
+ */
+ def typedActorFor[T <: AnyRef](implicit manifest: Manifest[T]): Option[AnyRef] = {
+ TypedActorModule.ensureTypedActorEnabled
+ def predicate(proxy: AnyRef) : Boolean = {
+ val actorRef = TypedActorModule.typedActorObjectInstance.get.actorFor(proxy)
+ actorRef.isDefined && manifest.erasure.isAssignableFrom(actorRef.get.actor.getClass)
+ }
+ findTypedActor({ case a:AnyRef if predicate(a) => a })
+ }
+
+ /**
+ * Finds all typed actors of type or sub-type specified by the class passed in as the Class argument.
+ */
+ def typedActorsFor[T <: AnyRef](clazz: Class[T]): Array[AnyRef] = {
+ TypedActorModule.ensureTypedActorEnabled
+ def predicate(proxy: AnyRef) : Boolean = {
+ val actorRef = TypedActorModule.typedActorObjectInstance.get.actorFor(proxy)
+ actorRef.isDefined && clazz.isAssignableFrom(actorRef.get.actor.getClass)
+ }
+ filterTypedActors(predicate)
+ }
+
+ /**
+ * Finds all typed actors that have a specific id.
+ */
+ def typedActorsFor(id: String): Array[AnyRef] = {
+ TypedActorModule.ensureTypedActorEnabled
+ val actorRefs = actorsById values id
+ actorRefs.flatMap(typedActorFor(_))
+ }
+
+ /**
+ * Finds the typed actor that has a specific UUID.
+ */
+ def typedActorFor(uuid: Uuid): Option[AnyRef] = {
+ TypedActorModule.ensureTypedActorEnabled
+ val actorRef = actorsByUUID get uuid
+ if (actorRef eq null)
+ None
+ else
+ typedActorFor(actorRef)
+ }
+
+ /**
+ * Get the typed actor proxy for a given typed actor ref.
+ */
+ private def typedActorFor(actorRef: ActorRef): Option[AnyRef] = {
+ TypedActorModule.typedActorObjectInstance.get.proxyFor(actorRef)
+ }
+
+
/**
* Registers an actor in the ActorRegistry.
*/
@@ -145,67 +265,130 @@ object ActorRegistry extends ListenerManagement {
*/
def shutdownAll() {
log.info("Shutting down all actors in the system...")
- foreach(_.stop)
+ if (TypedActorModule.isTypedActorEnabled) {
+ val elements = actorsByUUID.elements
+ while (elements.hasMoreElements) {
+ val actorRef = elements.nextElement
+ val proxy = typedActorFor(actorRef)
+ if (proxy.isDefined) {
+ TypedActorModule.typedActorObjectInstance.get.stop(proxy.get)
+ } else {
+ actorRef.stop
+ }
+ }
+ } else {
+ foreach(_.stop)
+ }
actorsByUUID.clear
actorsById.clear
log.info("All actors have been shut down and unregistered from ActorRegistry")
}
+
+ /**
+ * Get the remote actors for the given server address. For internal use only.
+ */
+ private[akka] def actorsFor(remoteServerAddress: Address): RemoteActorSet = guard.withWriteGuard {
+ remoteActorSets.getOrElseUpdate(remoteServerAddress, new RemoteActorSet)
+ }
+
+ private[akka] def registerActorByUuid(address: InetSocketAddress, uuid: String, actor: ActorRef) {
+ actorsByUuid(Address(address.getHostName, address.getPort)).putIfAbsent(uuid, actor)
+ }
+
+ private[akka] def registerTypedActorByUuid(address: InetSocketAddress, uuid: String, typedActor: AnyRef) {
+ typedActorsByUuid(Address(address.getHostName, address.getPort)).putIfAbsent(uuid, typedActor)
+ }
+
+ private[akka] def actors(address: Address) = actorsFor(address).actors
+ private[akka] def actorsByUuid(address: Address) = actorsFor(address).actorsByUuid
+ private[akka] def typedActors(address: Address) = actorsFor(address).typedActors
+ private[akka] def typedActorsByUuid(address: Address) = actorsFor(address).typedActorsByUuid
+
+ private[akka] class RemoteActorSet {
+ private[ActorRegistry] val actors = new ConcurrentHashMap[String, ActorRef]
+ private[ActorRegistry] val actorsByUuid = new ConcurrentHashMap[String, ActorRef]
+ private[ActorRegistry] val typedActors = new ConcurrentHashMap[String, AnyRef]
+ private[ActorRegistry] val typedActorsByUuid = new ConcurrentHashMap[String, AnyRef]
+ }
}
+/**
+ * An implementation of a ConcurrentMultiMap
+ * Adds/remove is serialized over the specified key
+ * Reads are fully concurrent <-- el-cheapo
+ *
+ * @author Viktor Klang
+ */
class Index[K <: AnyRef,V <: AnyRef : Manifest] {
- import scala.collection.JavaConversions._
-
private val Naught = Array[V]() //Nil for Arrays
private val container = new ConcurrentHashMap[K, JSet[V]]
private val emptySet = new ConcurrentSkipListSet[V]
- def put(key: K, value: V) {
-
- //Returns whether it needs to be retried or not
- def tryPut(set: JSet[V], v: V): Boolean = {
- set.synchronized {
- if (set.isEmpty) true //IF the set is empty then it has been removed, so signal retry
- else { //Else add the value to the set and signal that retry is not needed
- set add v
- false
- }
- }
- }
-
- @tailrec def syncPut(k: K, v: V): Boolean = {
+ /**
+ * Associates the value of type V with the key of type K
+ * @returns true if the value didn't exist for the key previously, and false otherwise
+ */
+ def put(key: K, value: V): Boolean = {
+ //Tailrecursive spin-locking put
+ @tailrec def spinPut(k: K, v: V): Boolean = {
var retry = false
+ var added = false
val set = container get k
- if (set ne null) retry = tryPut(set,v)
+
+ if (set ne null) {
+ set.synchronized {
+ if (set.isEmpty) {
+ retry = true //IF the set is empty then it has been removed, so signal retry
+ }
+ else { //Else add the value to the set and signal that retry is not needed
+ added = set add v
+ retry = false
+ }
+ }
+ }
else {
val newSet = new ConcurrentSkipListSet[V]
newSet add v
// Parry for two simultaneous putIfAbsent(id,newSet)
val oldSet = container.putIfAbsent(k,newSet)
- if (oldSet ne null)
- retry = tryPut(oldSet,v)
+ if (oldSet ne null) {
+ oldSet.synchronized {
+ if (oldSet.isEmpty) {
+ retry = true //IF the set is empty then it has been removed, so signal retry
+ }
+ else { //Else try to add the value to the set and signal that retry is not needed
+ added = oldSet add v
+ retry = false
+ }
+ }
+ } else {
+ added = true
+ }
}
- if (retry) syncPut(k,v)
- else true
+ if (retry) spinPut(k,v)
+ else added
}
- syncPut(key,value)
+ spinPut(key,value)
}
- def values(key: K) = {
+ /**
+ * @returns a _new_ array of all existing values for the given key at the time of the call
+ */
+ def values(key: K): Array[V] = {
val set: JSet[V] = container get key
- if (set ne null) set toArray Naught
- else Naught
- }
-
- def foreach(key: K)(fun: (V) => Unit) {
- val set = container get key
- if (set ne null)
- set foreach fun
+ val result = if (set ne null) set toArray Naught else Naught
+ result.asInstanceOf[Array[V]]
}
+ /**
+ * @returns Some(value) for the first matching value where the supplied function returns true for the given key,
+ * if no matches it returns None
+ */
def findValue(key: K)(f: (V) => Boolean): Option[V] = {
+ import scala.collection.JavaConversions._
val set = container get key
if (set ne null)
set.iterator.find(f)
@@ -213,23 +396,43 @@ class Index[K <: AnyRef,V <: AnyRef : Manifest] {
None
}
+ /**
+ * Applies the supplied function to all keys and their values
+ */
def foreach(fun: (K,V) => Unit) {
+ import scala.collection.JavaConversions._
container.entrySet foreach {
(e) => e.getValue.foreach(fun(e.getKey,_))
}
}
- def remove(key: K, value: V) {
+ /**
+ * Disassociates the value of type V from the key of type K
+ * @returns true if the value was disassociated from the key and false if it wasn't previously associated with the key
+ */
+ def remove(key: K, value: V): Boolean = {
val set = container get key
+
if (set ne null) {
set.synchronized {
if (set.remove(value)) { //If we can remove the value
if (set.isEmpty) //and the set becomes empty
container.remove(key,emptySet) //We try to remove the key if it's mapped to an empty set
+
+ true //Remove succeeded
}
+ else false //Remove failed
}
- }
+ } else false //Remove failed
}
- def clear = { foreach(remove _) }
+ /**
+ * @returns true if the underlying containers is empty, may report false negatives when the last remove is underway
+ */
+ def isEmpty: Boolean = container.isEmpty
+
+ /**
+ * Removes all keys and all values
+ */
+ def clear = foreach { case (k,v) => remove(k,v) }
}
\ No newline at end of file
diff --git a/akka-actor/src/main/scala/actor/Agent.scala b/akka-actor/src/main/scala/actor/Agent.scala
index e5b00d4f5e..6b9385ca4e 100644
--- a/akka-actor/src/main/scala/actor/Agent.scala
+++ b/akka-actor/src/main/scala/actor/Agent.scala
@@ -6,7 +6,7 @@ package se.scalablesolutions.akka.actor
import se.scalablesolutions.akka.stm.Ref
import se.scalablesolutions.akka.AkkaException
-import se.scalablesolutions.akka.util.{ Function => JFunc, Procedure => JProc }
+import se.scalablesolutions.akka.japi.{ Function => JFunc, Procedure => JProc }
import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.CountDownLatch
diff --git a/akka-actor/src/main/scala/actor/Supervisor.scala b/akka-actor/src/main/scala/actor/Supervisor.scala
index f575cda299..ba559e6945 100644
--- a/akka-actor/src/main/scala/actor/Supervisor.scala
+++ b/akka-actor/src/main/scala/actor/Supervisor.scala
@@ -29,10 +29,10 @@ class SupervisorException private[akka](message: String) extends AkkaException(m
* RestartStrategy(OneForOne, 3, 10, List(classOf[Exception]),
* Supervise(
* myFirstActor,
- * LifeCycle(Permanent)) ::
+ * Permanent) ::
* Supervise(
* mySecondActor,
- * LifeCycle(Permanent)) ::
+ * Permanent) ::
* Nil))
*
*
@@ -60,10 +60,10 @@ object Supervisor {
* RestartStrategy(OneForOne, 3, 10, List(classOf[Exception]),
* Supervise(
* myFirstActor,
- * LifeCycle(Permanent)) ::
+ * Permanent) ::
* Supervise(
* mySecondActor,
- * LifeCycle(Permanent)) ::
+ * Permanent) ::
* Nil))
*
*
@@ -79,14 +79,14 @@ object Supervisor {
object SupervisorFactory {
def apply(config: SupervisorConfig) = new SupervisorFactory(config)
- private[akka] def retrieveFaultHandlerAndTrapExitsFrom(config: SupervisorConfig):
- Tuple2[FaultHandlingStrategy, List[Class[_ <: Throwable]]] = config match {
- case SupervisorConfig(RestartStrategy(scheme, maxNrOfRetries, timeRange, trapExceptions), _) =>
- scheme match {
- case AllForOne => (AllForOneStrategy(maxNrOfRetries, timeRange), trapExceptions)
- case OneForOne => (OneForOneStrategy(maxNrOfRetries, timeRange), trapExceptions)
- }
- }
+ private[akka] def retrieveFaultHandlerAndTrapExitsFrom(config: SupervisorConfig): FaultHandlingStrategy =
+ config match {
+ case SupervisorConfig(RestartStrategy(scheme, maxNrOfRetries, timeRange, trapExceptions), _) =>
+ scheme match {
+ case AllForOne => AllForOneStrategy(trapExceptions,maxNrOfRetries, timeRange)
+ case OneForOne => OneForOneStrategy(trapExceptions,maxNrOfRetries, timeRange)
+ }
+ }
}
/**
@@ -99,9 +99,8 @@ class SupervisorFactory private[akka] (val config: SupervisorConfig) extends Log
def newInstance: Supervisor = newInstanceFor(config)
- def newInstanceFor(config: SupervisorConfig): Supervisor = {
- val (handler, trapExits) = SupervisorFactory.retrieveFaultHandlerAndTrapExitsFrom(config)
- val supervisor = new Supervisor(handler, trapExits)
+ def newInstanceFor(config: SupervisorConfig): Supervisor = {
+ val supervisor = new Supervisor(SupervisorFactory.retrieveFaultHandlerAndTrapExitsFrom(config))
supervisor.configure(config)
supervisor.start
supervisor
@@ -121,13 +120,13 @@ class SupervisorFactory private[akka] (val config: SupervisorConfig) extends Log
* @author Jonas Bonér
*/
sealed class Supervisor private[akka] (
- handler: FaultHandlingStrategy, trapExceptions: List[Class[_ <: Throwable]]) {
+ handler: FaultHandlingStrategy) {
import Supervisor._
private val _childActors = new ConcurrentHashMap[String, List[ActorRef]]
private val _childSupervisors = new CopyOnWriteArrayList[Supervisor]
- private[akka] val supervisor = actorOf(new SupervisorActor(handler, trapExceptions)).start
+ private[akka] val supervisor = actorOf(new SupervisorActor(handler)).start
def uuid = supervisor.uuid
@@ -160,7 +159,7 @@ sealed class Supervisor private[akka] (
else list
}
_childActors.put(className, actorRef :: currentActors)
- actorRef.lifeCycle = Some(lifeCycle)
+ actorRef.lifeCycle = lifeCycle
supervisor.link(actorRef)
remoteAddress.foreach { address =>
RemoteServerModule.registerActor(
@@ -179,13 +178,9 @@ sealed class Supervisor private[akka] (
*
* @author Jonas Bonér
*/
-final class SupervisorActor private[akka] (
- handler: FaultHandlingStrategy,
- trapExceptions: List[Class[_ <: Throwable]]) extends Actor {
+final class SupervisorActor private[akka] (handler: FaultHandlingStrategy) extends Actor {
import self._
-
- trapExit = trapExceptions
- faultHandler = Some(handler)
+ faultHandler = handler
override def postStop(): Unit = shutdownLinkedActors
diff --git a/akka-actor/src/main/scala/config/Config.scala b/akka-actor/src/main/scala/config/Config.scala
index c9d9a4968b..e97347754b 100644
--- a/akka-actor/src/main/scala/config/Config.scala
+++ b/akka-actor/src/main/scala/config/Config.scala
@@ -32,15 +32,36 @@ object Config {
System.setProperty("org.multiverse.api.GlobalStmInstance.factorymethod", "org.multiverse.stms.alpha.AlphaStm.createFast")
val HOME = {
- val systemHome = System.getenv("AKKA_HOME")
- if (systemHome == null || systemHome.length == 0 || systemHome == ".") {
- val optionHome = System.getProperty("akka.home", "")
- if (optionHome.length != 0) Some(optionHome)
- else None
- } else Some(systemHome)
+ val envHome = System.getenv("AKKA_HOME") match {
+ case null | "" | "." => None
+ case value => Some(value)
+ }
+
+ val systemHome = System.getProperty("akka.home") match {
+ case null | "" => None
+ case value => Some(value)
+ }
+
+ envHome orElse systemHome
}
val config = {
+
+ val confName = {
+
+ val envConf = System.getenv("AKKA_MODE") match {
+ case null | "" => None
+ case value => Some(value)
+ }
+
+ val systemConf = System.getProperty("akka.mode") match {
+ case null | "" => None
+ case value => Some(value)
+ }
+
+ (envConf orElse systemConf).map("akka." + _ + ".conf").getOrElse("akka.conf")
+ }
+
if (System.getProperty("akka.config", "") != "") {
val configFile = System.getProperty("akka.config", "")
try {
@@ -52,19 +73,9 @@ object Config {
"\n\tdue to: " + e.toString)
}
Configgy.config
- } else if (getClass.getClassLoader.getResource("akka.conf") != null) {
+ } else if (HOME.isDefined) {
try {
- Configgy.configureFromResource("akka.conf", getClass.getClassLoader)
- ConfigLogger.log.info("Config loaded from the application classpath.")
- } catch {
- case e: ParseException => throw new ConfigurationException(
- "Can't load 'akka.conf' config file from application classpath," +
- "\n\tdue to: " + e.toString)
- }
- Configgy.config
- } else if (HOME.isDefined) {
- try {
- val configFile = HOME.getOrElse(throwNoAkkaHomeException) + "/config/akka.conf"
+ val configFile = HOME.getOrElse(throwNoAkkaHomeException) + "/config/" + confName
Configgy.configure(configFile)
ConfigLogger.log.info(
"AKKA_HOME is defined as [%s], config loaded from [%s].",
@@ -73,18 +84,28 @@ object Config {
} catch {
case e: ParseException => throw new ConfigurationException(
"AKKA_HOME is defined as [" + HOME.get + "] " +
- "\n\tbut the 'akka.conf' config file can not be found at [" + HOME.get + "/config/akka.conf]," +
+ "\n\tbut the 'akka.conf' config file can not be found at [" + HOME.get + "/config/"+ confName + "]," +
+ "\n\tdue to: " + e.toString)
+ }
+ Configgy.config
+ } else if (getClass.getClassLoader.getResource(confName) ne null) {
+ try {
+ Configgy.configureFromResource(confName, getClass.getClassLoader)
+ ConfigLogger.log.info("Config [%s] loaded from the application classpath.",confName)
+ } catch {
+ case e: ParseException => throw new ConfigurationException(
+ "Can't load '" + confName + "' config file from application classpath," +
"\n\tdue to: " + e.toString)
}
Configgy.config
} else {
ConfigLogger.log.warning(
- "\nCan't load 'akka.conf'." +
- "\nOne of the three ways of locating the 'akka.conf' file needs to be defined:" +
+ "\nCan't load '" + confName + "'." +
+ "\nOne of the three ways of locating the '" + confName + "' file needs to be defined:" +
"\n\t1. Define the '-Dakka.config=...' system property option." +
- "\n\t2. Put the 'akka.conf' file on the classpath." +
+ "\n\t2. Put the '" + confName + "' file on the classpath." +
"\n\t3. Define 'AKKA_HOME' environment variable pointing to the root of the Akka distribution." +
- "\nI have no way of finding the 'akka.conf' configuration file." +
+ "\nI have no way of finding the '" + confName + "' configuration file." +
"\nUsing default values everywhere.")
CConfig.fromString("@@ -71,13 +63,11 @@ object HawtDispatcher { * * @return true if the actor was pinned */ - def pin(actorRef: ActorRef) = { - actorRef.mailbox match { - case x:HawtDispatcherMailbox=> - x.queue.setTargetQueue( getRandomThreadQueue ) - true - case _ => false - } + def pin(actorRef: ActorRef) = actorRef.mailbox match { + case x: HawtDispatcherMailbox => + x.queue.setTargetQueue( getRandomThreadQueue ) + true + case _ => false } /** @@ -91,19 +81,14 @@ object HawtDispatcher { *
* @return true if the actor was unpinned */ - def unpin(actorRef: ActorRef) = { - target(actorRef, globalQueue) - } + def unpin(actorRef: ActorRef) = target(actorRef, globalQueue) /** * @return true if the actor was pinned to a thread. */ - def pinned(actorRef: ActorRef):Boolean = { - actorRef.mailbox match { - case x:HawtDispatcherMailbox=> - x.queue.getTargetQueue.getQueueType == QueueType.THREAD_QUEUE - case _ => false - } + def pinned(actorRef: ActorRef):Boolean = actorRef.mailbox match { + case x: HawtDispatcherMailbox => x.queue.getTargetQueue.getQueueType == QueueType.THREAD_QUEUE + case _ => false } /** @@ -117,15 +102,12 @@ object HawtDispatcher { * * @return true if the actor was unpinned */ - def target(actorRef: ActorRef, parent:DispatchQueue) = { - actorRef.mailbox match { - case x:HawtDispatcherMailbox=> - x.queue.setTargetQueue( parent ) - true - case _ => false - } + def target(actorRef: ActorRef, parent: DispatchQueue) = actorRef.mailbox match { + case x: HawtDispatcherMailbox => + x.queue.setTargetQueue(parent) + true + case _ => false } - } /** @@ -156,25 +138,22 @@ object HawtDispatcher { * * @author Hiram Chirino */ -class HawtDispatcher(val aggregate:Boolean=true, val parent:DispatchQueue=globalQueue) extends MessageDispatcher { +class HawtDispatcher(val aggregate: Boolean = true, val parent: DispatchQueue = globalQueue) extends MessageDispatcher { import HawtDispatcher._ + private val active = new AtomicBoolean(false) - def start = { - if( active.compareAndSet(false, true) ) { - retainNonDaemon - } - } + val mailboxType: Option[MailboxType] = None + + def start = if (active.compareAndSet(false, true)) retainNonDaemon - def shutdown = { - if( active.compareAndSet(true, false) ) { - releaseNonDaemon - } - } + def execute(task: Runnable) {} + + def shutdown = if (active.compareAndSet(true, false)) releaseNonDaemon def isShutdown = !active.get - def dispatch(invocation: MessageInvocation) = if(active.get()) { + def dispatch(invocation: MessageInvocation) = if (active.get()) { mailbox(invocation.receiver).dispatch(invocation) } else { log.warning("%s is shut down,\n\tignoring the the messages sent to\n\t%s", toString, invocation.receiver) @@ -191,11 +170,18 @@ class HawtDispatcher(val aggregate:Boolean=true, val parent:DispatchQueue=global else new HawtDispatcherMailbox(queue) } - override def toString = "HawtDispatchEventDrivenDispatcher" + def createTransientMailbox(actorRef: ActorRef, mailboxType: TransientMailboxType): AnyRef = null.asInstanceOf[AnyRef] + + /** + * Creates and returns a durable mailbox for the given actor. + */ + protected def createDurableMailbox(actorRef: ActorRef, mailboxType: DurableMailboxType): AnyRef = null.asInstanceOf[AnyRef] + + override def toString = "HawtDispatcher" } -class HawtDispatcherMailbox(val queue:DispatchQueue) { - def dispatch(invocation: MessageInvocation):Unit = { +class HawtDispatcherMailbox(val queue: DispatchQueue) { + def dispatch(invocation: MessageInvocation) { queue { invocation.invoke } @@ -207,14 +193,10 @@ class AggregatingHawtDispatcherMailbox(queue:DispatchQueue) extends HawtDispatch source.setEventHandler (^{drain_source} ) source.resume - private def drain_source = { - source.getData.foreach { invocation => - invocation.invoke - } - } + private def drain_source = source.getData.foreach(_.invoke) - override def dispatch(invocation: MessageInvocation):Unit = { - if ( getCurrentQueue == null ) { + override def dispatch(invocation: MessageInvocation) { + if (getCurrentQueue eq null) { // we are being call from a non hawtdispatch thread, can't aggregate // it's events super.dispatch(invocation) diff --git a/akka-actor/src/main/scala/dispatch/MailboxHandling.scala b/akka-actor/src/main/scala/dispatch/MailboxHandling.scala new file mode 100644 index 0000000000..192313f178 --- /dev/null +++ b/akka-actor/src/main/scala/dispatch/MailboxHandling.scala @@ -0,0 +1,107 @@ +/** + * Copyright (C) 2009-2010 Scalable Solutions ABOption
+ * are either instances of case class Some or it is case
+ * object None.
+ *
+ * Java API
+ */
+sealed abstract class Option[A] extends java.lang.Iterable[A] {
+ import scala.collection.JavaConversions._
+
+ def get: A
+ def isEmpty: Boolean
+ def isDefined = !isEmpty
+ def asScala: scala.Option[A]
+ def iterator = if (isEmpty) Iterator.empty else Iterator.single(get)
+}
+
+object Option {
+ /**
+ *
+ * Java API.
*/
- protected def context_= (context: CamelContext) { _context = context }
+ def getContext: JOption[CamelContext] = context
/**
- * Sets the managed ProducerTemplate.
+ * Returns
+ * Java API.
*/
- protected def template_= (template: ProducerTemplate) { _template = template }
+ def getTemplate: JOption[ProducerTemplate] = template
+
+ /**
+ * Returns the current
+ * Java API.
+ */
+ def getMandatoryContext = mandatoryContext
+
+ /**
+ * Returns the current
+ * Java API.
+ */
+ def getMandatoryTemplate = mandatoryTemplate
def initialized = _initialized
def started = _started
/**
- * Starts the CamelContext and ProducerTemplate.
+ * Starts the CamelContext and an associated ProducerTemplate.
*/
def start = {
- context.start
- template.start
- _started = true
- log.info("Camel context started")
+ for {
+ c <- context
+ t <- template
+ } {
+ c.start
+ t.start
+ _started = true
+ log.info("Camel context started")
+ }
}
/**
- * Stops the CamelContext and ProducerTemplate.
+ * Stops the CamelContext and the associated ProducerTemplate.
*/
def stop = {
- template.stop
- context.stop
- _initialized = false
- _started = false
- log.info("Camel context stopped")
+ for {
+ t <- template
+ c <- context
+ } {
+ t.stop
+ c.stop
+ _started = false
+ _initialized = false
+ log.info("Camel context stopped")
+ }
}
/**
@@ -90,29 +141,62 @@ trait CamelContextLifecycle extends Logging {
/**
* Initializes this lifecycle object with the given CamelContext. For the passed
- * CamelContext stream-caching is enabled. If applications want to disable stream-
+ * CamelContext, stream-caching is enabled. If applications want to disable stream-
* caching they can do so after this method returned and prior to calling start.
- * This method also registers a new
- * {@link se.scalablesolutions.akka.camel.component.TypedActorComponent} at
- *
+ * Java API.
+ */
+ override def getContext: JOption[CamelContext] = super.getContext
+
+ /**
+ * see CamelContextLifecycle.getTemplate
+ *
+ * Java API.
+ */
+ override def getTemplate: JOption[ProducerTemplate] = super.getTemplate
+
+ /**
+ * see CamelContextLifecycle.getMandatoryContext
+ *
+ * Java API.
+ */
+ override def getMandatoryContext = super.getMandatoryContext
+
+ /**
+ * see CamelContextLifecycle.getMandatoryTemplate
+ *
+ * Java API.
+ */
+ override def getMandatoryTemplate = super.getMandatoryTemplate
}
diff --git a/akka-camel/src/main/scala/CamelService.scala b/akka-camel/src/main/scala/CamelService.scala
index 5fd8c9a66c..d53ff07dec 100644
--- a/akka-camel/src/main/scala/CamelService.scala
+++ b/akka-camel/src/main/scala/CamelService.scala
@@ -9,12 +9,15 @@ import org.apache.camel.CamelContext
import se.scalablesolutions.akka.actor.Actor._
import se.scalablesolutions.akka.actor.{AspectInitRegistry, ActorRegistry}
-import se.scalablesolutions.akka.util.{Bootable, Logging}
+import se.scalablesolutions.akka.config.Config._
+import se.scalablesolutions.akka.japi.{Option => JOption}
+import se.scalablesolutions.akka.util.{Logging, Bootable}
/**
- * Used by applications (and the Kernel) to publish consumer actors and typed actors via
- * Camel endpoints and to manage the life cycle of a a global CamelContext which can be
- * accessed via
+ * Java API
+ */
+ def getService: JOption[CamelService] = CamelServiceManager.service
+
+ /**
+ * Returns
+ * Java API
+ */
+ def getMandatoryService = mandatoryService
private[camel] def register(service: CamelService) =
if (_current.isDefined) throw new IllegalStateException("current CamelService already registered")
@@ -159,12 +183,12 @@ object CamelServiceManager {
*/
object CamelServiceFactory {
/**
- * Creates a new CamelService instance
+ * Creates a new CamelService instance.
*/
def createCamelService: CamelService = new CamelService { }
/**
- * Creates a new CamelService instance
+ * Creates a new CamelService instance and initializes it with the given CamelContext.
*/
def createCamelService(camelContext: CamelContext): CamelService = {
CamelContextManager.init(camelContext)
diff --git a/akka-camel/src/main/scala/Consumer.scala b/akka-camel/src/main/scala/Consumer.scala
index ea07757a9c..db04c46abf 100644
--- a/akka-camel/src/main/scala/Consumer.scala
+++ b/akka-camel/src/main/scala/Consumer.scala
@@ -20,30 +20,24 @@ trait Consumer { self: Actor =>
def endpointUri: String
/**
- * Determines whether two-way communications with this consumer actor should
- * be done in blocking or non-blocking mode (default is non-blocking). One-way
- * communications never block.
+ * Determines whether two-way communications between an endpoint and this consumer actor
+ * should be done in blocking or non-blocking mode (default is non-blocking). This method
+ * doesn't have any effect on one-way communications (they'll never block).
*/
def blocking = false
}
/**
- * Java-friendly {@link Consumer} inherited by
+ * Java-friendly Consumer.
*
- *
* Please note that this adapter can only be used locally at the moment which should not
- * be a problem is most situations as Camel endpoints are only activated for local actor references,
+ * be a problem is most situations since Camel endpoints are only activated for local actor references,
* never for remote references.
*
* @author Martin Krasser
@@ -207,8 +215,9 @@ private[akka] class AsyncCallbackAdapter(exchange: Exchange, callback: AsyncCall
}
/**
- * Writes the reply Option factory that creates Some
+ */
+ def some[A](v: A): Option[A] = Some(v)
+
+ /**
+ * Option factory that creates None
+ */
+ def none[A] = None.asInstanceOf[Option[A]]
+
+ /**
+ * Option factory that creates None if
+ * v is null, Some(v) otherwise.
+ */
+ def option[A](v: A): Option[A] = if (v == null) none else some(v)
+
+ /**
+ * Class Some[A] represents existing values of type
+ * A.
+ */
+ final case class Some[A](v: A) extends Option[A] {
+ def get = v
+ def isEmpty = false
+ def asScala = scala.Some(v)
+ }
+
+ /**
+ * This case object represents non-existent values.
+ */
+ private case object None extends Option[Nothing] {
+ def get = throw new NoSuchElementException("None.get")
+ def isEmpty = true
+ def asScala = scala.None
+ }
+
+ implicit def java2ScalaOption[A](o: Option[A]): scala.Option[A] = o.asScala
+ implicit def scala2JavaOption[A](o: scala.Option[A]): Option[A] = option(o.get)
+}
\ No newline at end of file
diff --git a/akka-actor/src/main/scala/stm/Transaction.scala b/akka-actor/src/main/scala/stm/Transaction.scala
index 60e0cd6772..9ea32d7ca6 100644
--- a/akka-actor/src/main/scala/stm/Transaction.scala
+++ b/akka-actor/src/main/scala/stm/Transaction.scala
@@ -165,7 +165,6 @@ object Transaction {
}
*/
override def equals(that: Any): Boolean = synchronized {
- that != null &&
that.isInstanceOf[Transaction] &&
that.asInstanceOf[Transaction].id == this.id
}
diff --git a/akka-actor/src/main/scala/util/Address.scala b/akka-actor/src/main/scala/util/Address.scala
new file mode 100644
index 0000000000..34c3f51bd4
--- /dev/null
+++ b/akka-actor/src/main/scala/util/Address.scala
@@ -0,0 +1,23 @@
+/**
+ * Copyright (C) 2009-2010 Scalable Solutions AB Some(CamelContext) (containing the current CamelContext)
+ * if CamelContextLifecycle has been initialized, otherwise None.
*/
- protected def context: CamelContext = _context
+ def context: Option[CamelContext] = _context
/**
- * Returns the managed ProducerTemplate.
+ * Returns Some(ProducerTemplate) (containing the current ProducerTemplate)
+ * if CamelContextLifecycle has been initialized, otherwise None.
*/
- protected def template: ProducerTemplate = _template
+ def template: Option[ProducerTemplate] = _template
/**
- * Sets the managed CamelContext.
+ * Returns Some(CamelContext) (containing the current CamelContext)
+ * if CamelContextLifecycle has been initialized, otherwise None.
+ * Some(ProducerTemplate) (containing the current ProducerTemplate)
+ * if CamelContextLifecycle has been initialized, otherwise None.
+ * CamelContext if this CamelContextLifecycle
+ * has been initialized, otherwise throws an IllegalStateException.
+ */
+ def mandatoryContext =
+ if (context.isDefined) context.get
+ else throw new IllegalStateException("no current CamelContext")
+
+ /**
+ * Returns the current ProducerTemplate if this CamelContextLifecycle
+ * has been initialized, otherwise throws an IllegalStateException.
+ */
+ def mandatoryTemplate =
+ if (template.isDefined) template.get
+ else throw new IllegalStateException("no current ProducerTemplate")
+
+ /**
+ * Returns the current CamelContext if this CamelContextLifecycle
+ * has been initialized, otherwise throws an IllegalStateException.
+ * ProducerTemplate if this CamelContextLifecycle
+ * has been initialized, otherwise throws an IllegalStateException.
+ * context under a name defined by TypedActorComponent.InternalSchema.
+ * This method also registers a new TypedActorComponent at the passes CamelContext
+ * under a name defined by TypedActorComponent.InternalSchema.
*/
def init(context: CamelContext) {
this.typedActorComponent = new TypedActorComponent
this.typedActorRegistry = typedActorComponent.typedActorRegistry
- this.context = context
- this.context.setStreamCaching(true)
- this.context.addComponent(TypedActorComponent.InternalSchema, typedActorComponent)
- this.template = context.createProducerTemplate
+
+ context.setStreamCaching(true)
+ context.addComponent(TypedActorComponent.InternalSchema, typedActorComponent)
+
+ this._context = Some(context)
+ this._template = Some(context.createProducerTemplate)
+
_initialized = true
log.info("Camel context initialized")
}
}
/**
- * Makes a global CamelContext and ProducerTemplate accessible to applications. The lifecycle
- * of these objects is managed by se.scalablesolutions.akka.camel.CamelService.
+ * Manages a global CamelContext and an associated ProducerTemplate.
*/
object CamelContextManager extends CamelContextLifecycle {
- override def context: CamelContext = super.context
- override def template: ProducerTemplate = super.template
+
+ // -----------------------------------------------------
+ // The inherited getters aren't statically accessible
+ // from Java. Therefore, they are redefined here.
+ // TODO: investigate if this is a Scala bug.
+ // -----------------------------------------------------
+
+ /**
+ * see CamelContextLifecycle.getContext
+ * se.scalablesolutions.akka.camel.CamelContextManager.context.
+ * Publishes (untyped) consumer actors and typed consumer actors via Camel endpoints. Actors
+ * are published (asynchronously) when they are started and unpublished (asynchronously) when
+ * they are stopped. The CamelService is notified about actor start- and stop-events by
+ * registering listeners at ActorRegistry and AspectInitRegistry.
*
* @author Martin Krasser
*/
@@ -29,16 +32,36 @@ trait CamelService extends Bootable with Logging {
AspectInitRegistry.addListener(publishRequestor)
/**
- * Starts the CamelService. Any started actor that is a consumer actor will be (asynchronously)
- * published as Camel endpoint. Consumer actors that are started after this method returned will
- * be published as well. Actor publishing is done asynchronously. A started (loaded) CamelService
- * also publishes @consume annotated methods of typed actors that have been created
- * with TypedActor.newInstance(..) (and TypedActor.newInstance(..)
- * on a remote node).
+ * Starts this CamelService unless akka.camel.service is set to false.
*/
abstract override def onLoad = {
super.onLoad
+ if (config.getBool("akka.camel.service", true)) start
+ }
+ /**
+ * Stops this CamelService unless akka.camel.service is set to false.
+ */
+ abstract override def onUnload = {
+ if (config.getBool("akka.camel.service", true)) stop
+ super.onUnload
+ }
+
+ @deprecated("use start() instead")
+ def load = start
+
+ @deprecated("use stop() instead")
+ def unload = stop
+
+ /**
+ * Starts this CamelService. Any started actor that is a consumer actor will be (asynchronously)
+ * published as Camel endpoint. Consumer actors that are started after this method returned will
+ * be published as well. Actor publishing is done asynchronously. A started (loaded) CamelService
+ * also publishes @consume annotated methods of typed actors that have been created
+ * with TypedActor.newInstance(..) (and TypedActor.newRemoteInstance(..)
+ * on a remote node).
+ */
+ def start: CamelService = {
// Only init and start if not already done by application
if (!CamelContextManager.initialized) CamelContextManager.init
if (!CamelContextManager.started) CamelContextManager.start
@@ -49,14 +72,16 @@ trait CamelService extends Bootable with Logging {
// init publishRequestor so that buffered and future events are delivered to consumerPublisher
publishRequestor ! PublishRequestorInit(consumerPublisher)
- // Register this instance as current CamelService
+ // Register this instance as current CamelService and return it
CamelServiceManager.register(this)
+ CamelServiceManager.mandatoryService
}
/**
- * Stops the CamelService.
+ * Stops this CamelService. All published consumer actors and typed consumer actor methods will be
+ * unpublished asynchronously.
*/
- abstract override def onUnload = {
+ def stop = {
// Unregister this instance as current CamelService
CamelServiceManager.unregister(this)
@@ -67,55 +92,27 @@ trait CamelService extends Bootable with Logging {
// Stop related services
consumerPublisher.stop
CamelContextManager.stop
-
- super.onUnload
- }
-
- @deprecated("use start() instead")
- def load: CamelService = {
- onLoad
- this
- }
-
- @deprecated("use stop() instead")
- def unload = onUnload
-
- /**
- * Starts the CamelService.
- *
- * @see onLoad
- */
- def start: CamelService = {
- onLoad
- this
}
/**
- * Stops the CamelService.
- *
- * @see onUnload
- */
- def stop = onUnload
-
- /**
- * Sets an expectation of the number of upcoming endpoint activations and returns
- * a {@link CountDownLatch} that can be used to wait for the activations to occur.
- * Endpoint activations that occurred in the past are not considered.
+ * Sets an expectation on the number of upcoming endpoint activations and returns
+ * a CountDownLatch that can be used to wait for the activations to occur. Endpoint
+ * activations that occurred in the past are not considered.
*/
def expectEndpointActivationCount(count: Int): CountDownLatch =
(consumerPublisher !! SetExpectedRegistrationCount(count)).as[CountDownLatch].get
/**
- * Sets an expectation of the number of upcoming endpoint de-activations and returns
- * a {@link CountDownLatch} that can be used to wait for the de-activations to occur.
- * Endpoint de-activations that occurred in the past are not considered.
+ * Sets an expectation on the number of upcoming endpoint de-activations and returns
+ * a CountDownLatch that can be used to wait for the de-activations to occur. Endpoint
+ * de-activations that occurred in the past are not considered.
*/
def expectEndpointDeactivationCount(count: Int): CountDownLatch =
(consumerPublisher !! SetExpectedUnregistrationCount(count)).as[CountDownLatch].get
}
/**
- * ...
+ * Manages a global CamelService (the 'current' CamelService).
*
* @author Martin Krasser
*/
@@ -128,22 +125,49 @@ object CamelServiceManager {
/**
* Starts a new CamelService and makes it the current CamelService.
+ *
+ * @see CamelService#start
+ * @see CamelService#onLoad
*/
def startCamelService = CamelServiceFactory.createCamelService.start
/**
* Stops the current CamelService.
+ *
+ * @see CamelService#stop
+ * @see CamelService#onUnload
*/
- def stopCamelService = service.stop
+ def stopCamelService = for (s <- service) s.stop
/**
- * Returns the current CamelService.
- *
- * @throws IllegalStateException if there's no current CamelService.
+ * Returns Some(CamelService) if this CamelService
+ * has been started, None otherwise.
*/
- def service =
+ def service = _current
+
+ /**
+ * Returns the current CamelService if CamelService
+ * has been started, otherwise throws an IllegalStateException.
+ * Some(CamelService) (containing the current CamelService)
+ * if this CamelServicehas been started, None otherwise.
+ */
+ def mandatoryService =
if (_current.isDefined) _current.get
- else throw new IllegalStateException("no current CamelService")
+ else throw new IllegalStateException("co current Camel service")
+
+ /**
+ * Returns Some(CamelService) (containing the current CamelService)
+ * if this CamelServicehas been started, None otherwise.
+ *
- *
- *
- * implementations.
+ * @see UntypedConsumerActor
+ * @see RemoteUntypedConsumerActor
+ * @see UntypedConsumerTransactor
*
* @author Martin Krasser
*/
trait UntypedConsumer extends Consumer { self: UntypedActor =>
-
final override def endpointUri = getEndpointUri
-
final override def blocking = isBlocking
/**
@@ -52,9 +46,9 @@ trait UntypedConsumer extends Consumer { self: UntypedActor =>
def getEndpointUri(): String
/**
- * Determines whether two-way communications with this consumer actor should
- * be done in blocking or non-blocking mode (default is non-blocking). One-way
- * communications never block.
+ * Determines whether two-way communications between an endpoint and this consumer actor
+ * should be done in blocking or non-blocking mode (default is non-blocking). This method
+ * doesn't have any effect on one-way communications (they'll never block).
*/
def isBlocking() = super.blocking
}
@@ -89,7 +83,7 @@ private[camel] object Consumer {
* reference with a target actor that implements the Consumer trait. The
* target Consumer object is passed as argument to f. This
* method returns None if actorRef is not a valid reference
- * to a consumer actor, Some result otherwise.
+ * to a consumer actor, Some consumer actor otherwise.
*/
def forConsumer[T](actorRef: ActorRef)(f: Consumer => T): Option[T] = {
if (!actorRef.actor.isInstanceOf[Consumer]) None
diff --git a/akka-camel/src/main/scala/ConsumerPublisher.scala b/akka-camel/src/main/scala/ConsumerPublisher.scala
index 472d7d6dad..f1bb5d7ab3 100644
--- a/akka-camel/src/main/scala/ConsumerPublisher.scala
+++ b/akka-camel/src/main/scala/ConsumerPublisher.scala
@@ -23,15 +23,15 @@ private[camel] object ConsumerPublisher extends Logging {
* Creates a route to the registered consumer actor.
*/
def handleConsumerRegistered(event: ConsumerRegistered) {
- CamelContextManager.context.addRoutes(new ConsumerActorRoute(event.uri, event.uuid, event.blocking))
+ CamelContextManager.mandatoryContext.addRoutes(new ConsumerActorRoute(event.uri, event.uuid, event.blocking))
log.info("published actor %s at endpoint %s" format (event.actorRef, event.uri))
}
/**
- * Stops route to the already un-registered consumer actor.
+ * Stops the route to the already un-registered consumer actor.
*/
def handleConsumerUnregistered(event: ConsumerUnregistered) {
- CamelContextManager.context.stopRoute(event.uuid.toString)
+ CamelContextManager.mandatoryContext.stopRoute(event.uuid.toString)
log.info("unpublished actor %s from endpoint %s" format (event.actorRef, event.uri))
}
@@ -43,29 +43,29 @@ private[camel] object ConsumerPublisher extends Logging {
val objectId = "%s_%s" format (event.init.actorRef.uuid, targetMethod)
CamelContextManager.typedActorRegistry.put(objectId, event.typedActor)
- CamelContextManager.context.addRoutes(new ConsumerMethodRoute(event.uri, objectId, targetMethod))
+ CamelContextManager.mandatoryContext.addRoutes(new ConsumerMethodRoute(event.uri, objectId, targetMethod))
log.info("published method %s of %s at endpoint %s" format (targetMethod, event.typedActor, event.uri))
}
/**
- * Stops route to the already un-registered consumer actor method.
+ * Stops the route to the already un-registered consumer actor method.
*/
def handleConsumerMethodUnregistered(event: ConsumerMethodUnregistered) {
val targetMethod = event.method.getName
val objectId = "%s_%s" format (event.init.actorRef.uuid, targetMethod)
CamelContextManager.typedActorRegistry.remove(objectId)
- CamelContextManager.context.stopRoute(objectId)
+ CamelContextManager.mandatoryContext.stopRoute(objectId)
log.info("unpublished method %s of %s from endpoint %s" format (targetMethod, event.typedActor, event.uri))
}
}
/**
* Actor that publishes consumer actors and typed actor methods at Camel endpoints.
- * The Camel context used for publishing is CamelContextManager.context. This actor
- * accepts messages of type
+ * The Camel context used for publishing is obtained via CamelContextManager.context.
+ * This actor accepts messages of type
* se.scalablesolutions.akka.camel.ConsumerRegistered,
- * se.scalablesolutions.akka.camel.ConsumerUnregistered.
+ * se.scalablesolutions.akka.camel.ConsumerUnregistered,
* se.scalablesolutions.akka.camel.ConsumerMethodRegistered and
* se.scalablesolutions.akka.camel.ConsumerMethodUnregistered.
*
@@ -110,7 +110,7 @@ private[camel] case class SetExpectedRegistrationCount(num: Int)
private[camel] case class SetExpectedUnregistrationCount(num: Int)
/**
- * Defines an abstract route to a target which is either an actor or an typed actor method..
+ * Abstract route to a target which is either an actor or an typed actor method.
*
* @param endpointUri endpoint URI of the consumer actor or typed actor method.
* @param id actor identifier or typed actor identifier (registry key).
@@ -135,9 +135,9 @@ private[camel] abstract class ConsumerRoute(endpointUri: String, id: String) ext
}
/**
- * Defines the route to a consumer actor.
+ * Defines the route to a (untyped) consumer actor.
*
- * @param endpointUri endpoint URI of the consumer actor
+ * @param endpointUri endpoint URI of the (untyped) consumer actor
* @param uuid actor uuid
* @param blocking true for blocking in-out exchanges, false otherwise
*
@@ -148,7 +148,7 @@ private[camel] class ConsumerActorRoute(endpointUri: String, uuid: Uuid, blockin
}
/**
- * Defines the route to an typed actor method..
+ * Defines the route to a typed actor method.
*
* @param endpointUri endpoint URI of the consumer actor method
* @param id typed actor identifier
@@ -162,10 +162,10 @@ private[camel] class ConsumerMethodRoute(val endpointUri: String, id: String, me
/**
* A registration listener that triggers publication of consumer actors and typed actor
- * methods as well as un-publication of consumer actors. This actor needs to be initialized
- * with a PublishRequestorInit command message for obtaining a reference to
- * a publisher actor. Before initialization it buffers all outbound messages
- * and delivers them to the publisher when receiving a
+ * methods as well as un-publication of consumer actors and typed actor methods. This actor
+ * needs to be initialized with a PublishRequestorInit command message for
+ * obtaining a reference to a publisher actor. Before initialization it buffers
+ * all outbound messages and delivers them to the publisher when receiving a
* PublishRequestorInit message. After initialization, outbound messages are
* delivered directly without buffering.
*
@@ -273,7 +273,7 @@ private[camel] case class ConsumerMethodUnregistered(typedActor: AnyRef, init: A
*/
private[camel] object ConsumerRegistered {
/**
- * Optionally creates an ConsumerRegistered event message for a consumer actor or None if
+ * Creates an ConsumerRegistered event message for a consumer actor or None if
* actorRef is not a consumer actor.
*/
def forConsumer(actorRef: ActorRef): Option[ConsumerRegistered] = {
@@ -288,7 +288,7 @@ private[camel] object ConsumerRegistered {
*/
private[camel] object ConsumerUnregistered {
/**
- * Optionally creates an ConsumerUnregistered event message for a consumer actor or None if
+ * Creates an ConsumerUnregistered event message for a consumer actor or None if
* actorRef is not a consumer actor.
*/
def forConsumer(actorRef: ActorRef): Option[ConsumerUnregistered] = {
@@ -327,8 +327,8 @@ private[camel] object ConsumerMethod {
*/
private[camel] object ConsumerMethodRegistered {
/**
- * Creates a list of ConsumerMethodRegistered event messages for an typed actor or an empty
- * list if the typed actor is a proxy for an remote typed actor or the typed actor doesn't
+ * Creates a list of ConsumerMethodRegistered event messages for a typed actor or an empty
+ * list if the typed actor is a proxy for a remote typed actor or the typed actor doesn't
* have any @consume annotated methods.
*/
def forConsumer(typedActor: AnyRef, init: AspectInit): List[ConsumerMethodRegistered] = {
@@ -343,8 +343,8 @@ private[camel] object ConsumerMethodRegistered {
*/
private[camel] object ConsumerMethodUnregistered {
/**
- * Creates a list of ConsumerMethodUnregistered event messages for an typed actor or an empty
- * list if the typed actor is a proxy for an remote typed actor or the typed actor doesn't
+ * Creates a list of ConsumerMethodUnregistered event messages for a typed actor or an empty
+ * list if the typed actor is a proxy for a remote typed actor or the typed actor doesn't
* have any @consume annotated methods.
*/
def forConsumer(typedActor: AnyRef, init: AspectInit): List[ConsumerMethodUnregistered] = {
diff --git a/akka-camel/src/main/scala/Message.scala b/akka-camel/src/main/scala/Message.scala
index a834568a22..7c503009e8 100644
--- a/akka-camel/src/main/scala/Message.scala
+++ b/akka-camel/src/main/scala/Message.scala
@@ -10,7 +10,7 @@ import org.apache.camel.util.ExchangeHelper
/**
* An immutable representation of a Camel message. Actor classes that mix in
* se.scalablesolutions.akka.camel.Producer or
- * se.scalablesolutions.akka.camel.Consumer use this message type for communication.
+ * se.scalablesolutions.akka.camel.Consumer usually use this message type for communication.
*
* @author Martin Krasser
*/
@@ -24,7 +24,7 @@ case class Message(val body: Any, val headers: Map[String, Any] = Map.empty) {
* @see CamelContextManager.
*/
def bodyAs[T](clazz: Class[T]): T =
- CamelContextManager.context.getTypeConverter.mandatoryConvertTo[T](clazz, body)
+ CamelContextManager.mandatoryContext.getTypeConverter.mandatoryConvertTo[T](clazz, body)
/**
* Returns the body of the message converted to the type T. Conversion is done
@@ -35,7 +35,7 @@ case class Message(val body: Any, val headers: Map[String, Any] = Map.empty) {
* @see CamelContextManager.
*/
def bodyAs[T](implicit m: Manifest[T]): T =
- CamelContextManager.context.getTypeConverter.mandatoryConvertTo[T](m.erasure.asInstanceOf[Class[T]], body)
+ CamelContextManager.mandatoryContext.getTypeConverter.mandatoryConvertTo[T](m.erasure.asInstanceOf[Class[T]], body)
/**
* Returns those headers from this message whose name is contained in names.
@@ -53,14 +53,14 @@ case class Message(val body: Any, val headers: Map[String, Any] = Map.empty) {
* NoSuchElementException if the header doesn't exist.
*/
def headerAs[T](name: String)(implicit m: Manifest[T]): T =
- CamelContextManager.context.getTypeConverter.mandatoryConvertTo[T](m.erasure.asInstanceOf[Class[T]], header(name))
+ CamelContextManager.mandatoryContext.getTypeConverter.mandatoryConvertTo[T](m.erasure.asInstanceOf[Class[T]], header(name))
/**
* Returns the header with given name converted to type given by the clazz
* argument. Throws NoSuchElementException if the header doesn't exist.
*/
def headerAs[T](name: String, clazz: Class[T]): T =
- CamelContextManager.context.getTypeConverter.mandatoryConvertTo[T](clazz, header(name))
+ CamelContextManager.mandatoryContext.getTypeConverter.mandatoryConvertTo[T](clazz, header(name))
/**
* Creates a Message with a new body using a transformer function.
@@ -264,8 +264,8 @@ class CamelMessageAdapter(val cm: CamelMessage) {
/**
* Defines conversion methods to CamelExchangeAdapter and CamelMessageAdapter.
- * Imported by applications
- * that implicitly want to use conversion methods of CamelExchangeAdapter and CamelMessageAdapter.
+ * Imported by applications that implicitly want to use conversion methods of
+ * CamelExchangeAdapter and CamelMessageAdapter.
*/
object CamelMessageConversion {
diff --git a/akka-camel/src/main/scala/Producer.scala b/akka-camel/src/main/scala/Producer.scala
index 0be07e9737..2924590c9e 100644
--- a/akka-camel/src/main/scala/Producer.scala
+++ b/akka-camel/src/main/scala/Producer.scala
@@ -24,10 +24,10 @@ trait ProducerSupport { this: Actor =>
private val headersToCopyDefault = Set(Message.MessageExchangeId)
/**
- * Endpoint object resolved from current CamelContext with
+ * Endpoint object resolved from the current CamelContext with
* endpointUri.
*/
- private lazy val endpoint = CamelContextManager.context.getEndpoint(endpointUri)
+ private lazy val endpoint = CamelContextManager.mandatoryContext.getEndpoint(endpointUri)
/**
* SendProcessor for producing messages to endpoint.
@@ -36,8 +36,8 @@ trait ProducerSupport { this: Actor =>
/**
* If set to false (default), this producer expects a response message from the Camel endpoint.
- * If set to true, this producer communicates with the Camel endpoint with an in-only message
- * exchange pattern (fire and forget).
+ * If set to true, this producer initiates an in-only message exchange with the Camel endpoint
+ * (fire and forget).
*/
def oneway: Boolean = false
@@ -62,13 +62,17 @@ trait ProducerSupport { this: Actor =>
}
/**
- * Produces msg as exchange of given pattern to the endpoint specified by
- * endpointUri. After producing to the endpoint the processing result is passed as argument
- * to receiveAfterProduce. If the result was returned synchronously by the endpoint then
- * receiveAfterProduce is called synchronously as well. If the result was returned asynchronously,
- * the receiveAfterProduce is called asynchronously as well. This is done by wrapping the result,
- * adding it to this producers mailbox, unwrapping it once it is received and calling
- * receiveAfterProduce. The original sender and senderFuture are thereby preserved.
+ * Initiates a message exchange of given pattern with the endpoint specified by
+ * endpointUri. The in-message of the initiated exchange is the canonical form
+ * of msg. After sending the in-message, the processing result (response) is passed
+ * as argument to receiveAfterProduce. If the response is received synchronously from
+ * the endpoint then receiveAfterProduce is called synchronously as well. If the
+ * response is received asynchronously, the receiveAfterProduce is called
+ * asynchronously. This is done by wrapping the response, adding it to this producers
+ * mailbox, unwrapping it and calling receiveAfterProduce. The original
+ * sender and senderFuture are thereby preserved.
+ *
+ * @see Message#canonicalize(Any)
*
* @param msg message to produce
* @param pattern exchange pattern
@@ -106,8 +110,8 @@ trait ProducerSupport { this: Actor =>
/**
* Produces msg to the endpoint specified by endpointUri. Before the message is
- * actually produced it is pre-processed by calling receiveBeforeProduce. If oneway
- * is true an in-only message exchange is initiated, otherwise an in-out message exchange.
+ * actually sent it is pre-processed by calling receiveBeforeProduce. If oneway
+ * is true, an in-only message exchange is initiated, otherwise an in-out message exchange.
*
* @see Producer#produce(Any, ExchangePattern)
*/
@@ -132,17 +136,18 @@ trait ProducerSupport { this: Actor =>
}
/**
- * Called after the a result was received from the endpoint specified by endpointUri. The
- * result is passed as argument. By default, this method replies the result back to the original sender
- * if oneway is false. If oneway is true then nothing is done. This method may
- * be overridden by subtraits or subclasses.
+ * Called after a response was received from the endpoint specified by endpointUri. The
+ * response is passed as argument. By default, this method sends the response back to the original sender
+ * if oneway is false. If oneway is true, nothing is
+ * done. This method may be overridden by subtraits or subclasses (e.g. to forward responses to another
+ * actor).
*/
protected def receiveAfterProduce: Receive = {
case msg => if (!oneway) self.reply(msg)
}
/**
- * Creates a new Exchange with given pattern from the endpoint specified by
+ * Creates a new Exchange of given pattern from the endpoint specified by
* endpointUri.
*/
private def createExchange(pattern: ExchangePattern): Exchange = endpoint.createExchange(pattern)
@@ -158,25 +163,26 @@ trait ProducerSupport { this: Actor =>
}
/**
- * Mixed in by Actor implementations that produce messages to Camel endpoints.
+ * Mixed in by Actor implementations to produce messages to Camel endpoints.
*/
trait Producer extends ProducerSupport { this: Actor =>
/**
- * Default implementation of Actor.receive
+ * Default implementation of Actor.receive. Any messages received by this actors
+ * will be produced to the endpoint specified by endpointUri.
*/
protected def receive = produce
}
/**
- * Java-friendly {@link ProducerSupport} inherited by {@link UntypedProducerActor} implementations.
+ * Java-friendly ProducerSupport.
+ *
+ * @see UntypedProducerActor
*
* @author Martin Krasser
*/
trait UntypedProducer extends ProducerSupport { this: UntypedActor =>
-
final override def endpointUri = getEndpointUri
-
final override def oneway = isOneway
final override def receiveBeforeProduce = {
@@ -213,10 +219,10 @@ trait UntypedProducer extends ProducerSupport { this: UntypedActor =>
def onReceiveBeforeProduce(message: Any): Any = super.receiveBeforeProduce(message)
/**
- * Called after the a result was received from the endpoint specified by getEndpointUri. The
- * result is passed as argument. By default, this method replies the result back to the original sender
- * if isOneway returns false. If isOneway returns true then nothing is done. This
- * method may be overridden by subclasses.
+ * Called after a response was received from the endpoint specified by endpointUri. The
+ * response is passed as argument. By default, this method sends the response back to the original sender
+ * if oneway is false. If oneway is true, nothing is
+ * done. This method may be overridden by subclasses (e.g. to forward responses to another actor).
*/
@throws(classOf[Exception])
def onReceiveAfterProduce(message: Any): Unit = super.receiveAfterProduce(message)
diff --git a/akka-camel/src/main/scala/component/ActorComponent.scala b/akka-camel/src/main/scala/component/ActorComponent.scala
index a9c96eebb9..297a4c3a84 100644
--- a/akka-camel/src/main/scala/component/ActorComponent.scala
+++ b/akka-camel/src/main/scala/component/ActorComponent.scala
@@ -14,16 +14,13 @@ import jsr166x.Deque
import org.apache.camel._
import org.apache.camel.impl.{DefaultProducer, DefaultEndpoint, DefaultComponent}
-import se.scalablesolutions.akka.camel.{Failure, CamelMessageConversion, Message}
-import CamelMessageConversion.toExchangeAdapter
+import se.scalablesolutions.akka.actor._
+import se.scalablesolutions.akka.camel.{Failure, Message}
+import se.scalablesolutions.akka.camel.CamelMessageConversion.toExchangeAdapter
import se.scalablesolutions.akka.dispatch.{CompletableFuture, MessageInvocation, MessageDispatcher}
import se.scalablesolutions.akka.stm.TransactionConfig
-import se.scalablesolutions.akka.actor.{ScalaActorRef, ActorRegistry, Actor, ActorRef, Uuid, uuidFrom}
-
-import se.scalablesolutions.akka.AkkaException
import scala.reflect.BeanProperty
-import se.scalablesolutions.akka.actor._
/**
* Camel component for sending messages to and receiving replies from (untyped) actors.
@@ -48,12 +45,13 @@ class ActorComponent extends DefaultComponent {
}
/**
- * Camel endpoint for referencing an (untyped) actor. The actor reference is given by the endpoint URI.
- * An actor can be referenced by its ActorRef.id or its ActorRef.uuid.
- * Supported endpoint URI formats are
- * actor:<actorid>,
- * actor:id:<actorid> and
- * actor:uuid:<actoruuid>.
+ * Camel endpoint for sending messages to and receiving replies from (untyped) actors. Actors
+ * are referenced using actor endpoint URIs of the following format:
+ * actor:,
+ * actor:id: and
+ * actor:uuid:,
+ * where actor-id refers to ActorRef.id and actor-uuid
+ * refers to the String-representation od ActorRef.uuid.
*
* @see se.scalablesolutions.akka.camel.component.ActorComponent
* @see se.scalablesolutions.akka.camel.component.ActorProducer
@@ -66,8 +64,9 @@ class ActorEndpoint(uri: String,
val uuid: Option[Uuid]) extends DefaultEndpoint(uri, comp) {
/**
- * Blocking of caller thread during two-way message exchanges with consumer actors. This is set
- * via the blocking=true|false endpoint URI parameter. If omitted blocking is false.
+ * Whether to block caller thread during two-way message exchanges with (untyped) actors. This is
+ * set via the blocking=true|false endpoint URI parameter. Default value is
+ * false.
*/
@BeanProperty var blocking: Boolean = false
@@ -89,9 +88,18 @@ class ActorEndpoint(uri: String,
}
/**
- * Sends the in-message of an exchange to an (untyped) actor. If the exchange pattern is out-capable and
- * blocking is enabled then the producer waits for a reply (using the !! operator),
- * otherwise the ! operator is used for sending the message.
+ * Sends the in-message of an exchange to an (untyped) actor.
+ *
+ *
*
* @see se.scalablesolutions.akka.camel.component.ActorComponent
* @see se.scalablesolutions.akka.camel.component.ActorEndpoint
@@ -186,11 +194,11 @@ private[akka] object AsyncCallbackAdapter {
}
/**
- * Adapts an blocking is set to
+ * true then the producer waits for a reply, using the !! operator.blocking is set to
+ * false then the producer sends the message using the ! operator, together
+ * with a callback handler. The callback handler is an ActorRef that can be
+ * used by the receiving actor to asynchronously reply to the route that is sending the
+ * message.AsyncCallback to ActorRef.!. Used by other actors to reply
- * asynchronously to Camel with ActorRef.reply.
+ * Adapts an ActorRef to a Camel AsyncCallback. Used by receiving actors to reply
+ * asynchronously to Camel routes with ActorRef.reply.
* message to exchange and uses callback to
- * generate completion notifications.
+ * Populates the initial exchange with the reply message and uses the
+ * callback handler to notify Camel about the asynchronous completion of the message
+ * exchange.
*
* @param message reply message
* @param sender ignored
diff --git a/akka-camel/src/main/scala/component/TypedActorComponent.scala b/akka-camel/src/main/scala/component/TypedActorComponent.scala
index 2a48cf9fc4..f172cc808b 100644
--- a/akka-camel/src/main/scala/component/TypedActorComponent.scala
+++ b/akka-camel/src/main/scala/component/TypedActorComponent.scala
@@ -21,7 +21,7 @@ object TypedActorComponent {
/**
* Camel component for exchanging messages with typed actors. This component
- * tries to obtain the typed actor from the typedActorRegistry
+ * tries to obtain the typed actor from its typedActorRegistry
* first. If it's not there it tries to obtain it from the CamelContext's registry.
*
* @see org.apache.camel.component.bean.BeanComponent
@@ -32,9 +32,9 @@ class TypedActorComponent extends BeanComponent {
val typedActorRegistry = new ConcurrentHashMap[String, AnyRef]
/**
- * Creates a {@link org.apache.camel.component.bean.BeanEndpoint} with a custom
- * bean holder that uses typedActorRegistry for getting access to
- * typed actors (beans).
+ * Creates an org.apache.camel.component.bean.BeanEndpoint with a custom
+ * bean holder that uses typedActorRegistry for getting access to typed
+ * actors (beans).
*
* @see se.scalablesolutions.akka.camel.component.TypedActorHolder
*/
@@ -51,7 +51,7 @@ class TypedActorComponent extends BeanComponent {
}
/**
- * {@link org.apache.camel.component.bean.BeanHolder} implementation that uses a custom
+ * org.apache.camel.component.bean.BeanHolder implementation that uses a custom
* registry for getting access to typed actors.
*
* @author Martin Krasser
@@ -60,13 +60,16 @@ class TypedActorHolder(typedActorRegistry: Map[String, AnyRef], context: CamelCo
extends RegistryBean(context, name) {
/**
- * Returns an {@link se.scalablesolutions.akka.camel.component.TypedActorInfo} instance.
+ * Returns an se.scalablesolutions.akka.camel.component.TypedActorInfo instance.
*/
override def getBeanInfo: BeanInfo =
new TypedActorInfo(getContext, getBean.getClass, getParameterMappingStrategy)
/**
- * Obtains an typed actor from typedActorRegistry.
+ * Obtains a typed actor from typedActorRegistry. If the typed actor cannot
+ * be found then this method tries to obtain the actor from the CamelContext's registry.
+ *
+ * @return a typed actor or null.
*/
override def getBean: AnyRef = {
val bean = typedActorRegistry.get(getName)
@@ -75,7 +78,7 @@ class TypedActorHolder(typedActorRegistry: Map[String, AnyRef], context: CamelCo
}
/**
- * Provides typed actor meta information.
+ * Typed actor meta information.
*
* @author Martin Krasser
*/
@@ -101,7 +104,7 @@ class TypedActorInfo(context: CamelContext, clazz: Class[_], strategy: Parameter
}
}
val superclass = clazz.getSuperclass
- if (superclass != null && !superclass.equals(classOf[AnyRef])) {
+ if ((superclass ne null) && !superclass.equals(classOf[AnyRef])) {
introspect(superclass)
}
}
diff --git a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/SampleUntypedForwardingProducer.java b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/SampleUntypedForwardingProducer.java
index e909947de8..bfa34f42e5 100644
--- a/akka-camel/src/test/java/se/scalablesolutions/akka/camel/SampleUntypedForwardingProducer.java
+++ b/akka-camel/src/test/java/se/scalablesolutions/akka/camel/SampleUntypedForwardingProducer.java
@@ -13,6 +13,6 @@ public class SampleUntypedForwardingProducer extends UntypedProducerActor {
public void onReceiveAfterProduce(Object message) {
Message msg = (Message)message;
String body = msg.bodyAs(String.class);
- CamelContextManager.template().sendBody("direct:forward-test-1", body);
+ CamelContextManager.getMandatoryTemplate().sendBody("direct:forward-test-1", body);
}
}
diff --git a/akka-camel/src/test/scala/CamelContextLifecycleTest.scala b/akka-camel/src/test/scala/CamelContextLifecycleTest.scala
index cf558ec8d9..6e6889c295 100644
--- a/akka-camel/src/test/scala/CamelContextLifecycleTest.scala
+++ b/akka-camel/src/test/scala/CamelContextLifecycleTest.scala
@@ -6,22 +6,30 @@ import org.scalatest.junit.JUnitSuite
class CamelContextLifecycleTest extends JUnitSuite with CamelContextLifecycle {
@Test def shouldManageCustomCamelContext {
- assert(context === null)
- assert(template === null)
+ assert(context === None)
+ assert(template === None)
+
+ intercept[IllegalStateException] { mandatoryContext }
+ intercept[IllegalStateException] { mandatoryTemplate }
+
val ctx = new TestCamelContext
assert(ctx.isStreamCaching === false)
+
init(ctx)
- assert(context.isStreamCaching === true)
- assert(!context.asInstanceOf[TestCamelContext].isStarted)
- // In Camel 2.3 CamelComtext.createProducerTemplate starts
- // the template before returning it (wasn't started in 2.2)
- assert(template.asInstanceOf[DefaultProducerTemplate].isStarted)
+
+ assert(mandatoryContext.isStreamCaching === true)
+ assert(!mandatoryContext.asInstanceOf[TestCamelContext].isStarted)
+ assert(mandatoryTemplate.asInstanceOf[DefaultProducerTemplate].isStarted)
+
start
- assert(context.asInstanceOf[TestCamelContext].isStarted)
- assert(template.asInstanceOf[DefaultProducerTemplate].isStarted)
+
+ assert(mandatoryContext.asInstanceOf[TestCamelContext].isStarted)
+ assert(mandatoryTemplate.asInstanceOf[DefaultProducerTemplate].isStarted)
+
stop
- assert(!context.asInstanceOf[TestCamelContext].isStarted)
- assert(!template.asInstanceOf[DefaultProducerTemplate].isStarted)
+
+ assert(!mandatoryContext.asInstanceOf[TestCamelContext].isStarted)
+ assert(!mandatoryTemplate.asInstanceOf[DefaultProducerTemplate].isStarted)
}
class TestCamelContext extends DefaultCamelContext
diff --git a/akka-camel/src/test/scala/CamelServiceManagerSpec.scala b/akka-camel/src/test/scala/CamelServiceManagerTest.scala
similarity index 72%
rename from akka-camel/src/test/scala/CamelServiceManagerSpec.scala
rename to akka-camel/src/test/scala/CamelServiceManagerTest.scala
index 222c1a17c6..712ffec70b 100644
--- a/akka-camel/src/test/scala/CamelServiceManagerSpec.scala
+++ b/akka-camel/src/test/scala/CamelServiceManagerTest.scala
@@ -8,21 +8,24 @@ import se.scalablesolutions.akka.actor.ActorRegistry
/**
* @author Martin Krasser
*/
-class CamelServiceManagerSpec extends WordSpec with BeforeAndAfterAll with MustMatchers {
+class CamelServiceManagerTest extends WordSpec with BeforeAndAfterAll with MustMatchers {
- override def afterAll = ActorRegistry.shutdownAll
+ override def afterAll = {
+ CamelServiceManager.stopCamelService
+ ActorRegistry.shutdownAll
+ }
"A CamelServiceManager" when {
"the startCamelService method been has been called" must {
"have registered the started CamelService instance" in {
val service = CamelServiceManager.startCamelService
- CamelServiceManager.service must be theSameInstanceAs (service)
+ CamelServiceManager.mandatoryService must be theSameInstanceAs (service)
}
}
"the stopCamelService method been has been called" must {
"have unregistered the current CamelService instance" in {
val service = CamelServiceManager.stopCamelService
- intercept[IllegalStateException] { CamelServiceManager.service }
+ CamelServiceManager.service must be (None)
}
}
}
@@ -32,13 +35,13 @@ class CamelServiceManagerSpec extends WordSpec with BeforeAndAfterAll with MustM
"a CamelService instance has been started externally" must {
"have registered the started CamelService instance" in {
service.start
- CamelServiceManager.service must be theSameInstanceAs (service)
+ CamelServiceManager.mandatoryService must be theSameInstanceAs (service)
}
}
"the current CamelService instance has been stopped externally" must {
"have unregistered the current CamelService instance" in {
service.stop
- intercept[IllegalStateException] { CamelServiceManager.service }
+ CamelServiceManager.service must be (None)
}
}
}
@@ -54,10 +57,6 @@ class CamelServiceManagerSpec extends WordSpec with BeforeAndAfterAll with MustM
"only allow the current CamelService instance to be stopped" in {
intercept[IllegalStateException] { CamelServiceFactory.createCamelService.stop }
}
- "ensure that the current CamelService instance has been actually started" in {
- CamelServiceManager.stopCamelService
- intercept[IllegalStateException] { CamelServiceManager.stopCamelService }
- }
}
}
}
diff --git a/akka-camel/src/test/scala/ConsumerSpec.scala b/akka-camel/src/test/scala/ConsumerTest.scala
similarity index 76%
rename from akka-camel/src/test/scala/ConsumerSpec.scala
rename to akka-camel/src/test/scala/ConsumerTest.scala
index 678ed70057..0af8aec7d5 100644
--- a/akka-camel/src/test/scala/ConsumerSpec.scala
+++ b/akka-camel/src/test/scala/ConsumerTest.scala
@@ -13,9 +13,9 @@ import se.scalablesolutions.akka.actor._
/**
* @author Martin Krasser
*/
-class ConsumerSpec extends WordSpec with BeforeAndAfterAll with MustMatchers {
- import CamelContextManager.template
- import ConsumerSpec._
+class ConsumerTest extends WordSpec with BeforeAndAfterAll with MustMatchers {
+ import CamelContextManager.mandatoryTemplate
+ import ConsumerTest._
var service: CamelService = _
@@ -45,12 +45,12 @@ class ConsumerSpec extends WordSpec with BeforeAndAfterAll with MustMatchers {
val consumer = actorOf(new TestConsumer("direct:publish-test-2"))
"started before starting the CamelService" must {
"support an in-out message exchange via its endpoint" in {
- template.requestBody("direct:publish-test-1", "msg1") must equal ("received msg1")
+ mandatoryTemplate.requestBody("direct:publish-test-1", "msg1") must equal ("received msg1")
}
}
"not started" must {
"not have an associated endpoint in the CamelContext" in {
- CamelContextManager.context.hasEndpoint("direct:publish-test-2") must be (null)
+ CamelContextManager.mandatoryContext.hasEndpoint("direct:publish-test-2") must be (null)
}
}
"started" must {
@@ -58,10 +58,10 @@ class ConsumerSpec extends WordSpec with BeforeAndAfterAll with MustMatchers {
val latch = service.expectEndpointActivationCount(1)
consumer.start
latch.await(5000, TimeUnit.MILLISECONDS) must be (true)
- template.requestBody("direct:publish-test-2", "msg2") must equal ("received msg2")
+ mandatoryTemplate.requestBody("direct:publish-test-2", "msg2") must equal ("received msg2")
}
"have an associated endpoint in the CamelContext" in {
- CamelContextManager.context.hasEndpoint("direct:publish-test-2") must not be (null)
+ CamelContextManager.mandatoryContext.hasEndpoint("direct:publish-test-2") must not be (null)
}
}
"stopped" must {
@@ -70,7 +70,7 @@ class ConsumerSpec extends WordSpec with BeforeAndAfterAll with MustMatchers {
consumer.stop
latch.await(5000, TimeUnit.MILLISECONDS) must be (true)
intercept[CamelExecutionException] {
- template.requestBody("direct:publish-test-2", "msg2")
+ mandatoryTemplate.requestBody("direct:publish-test-2", "msg2")
}
}
}
@@ -83,9 +83,9 @@ class ConsumerSpec extends WordSpec with BeforeAndAfterAll with MustMatchers {
val latch = service.expectEndpointActivationCount(3)
actor = TypedActor.newInstance(classOf[SampleTypedConsumer], classOf[SampleTypedConsumerImpl])
latch.await(5000, TimeUnit.MILLISECONDS) must be (true)
- template.requestBodyAndHeader("direct:m2", "x", "test", "y") must equal ("m2: x y")
- template.requestBodyAndHeader("direct:m3", "x", "test", "y") must equal ("m3: x y")
- template.requestBodyAndHeader("direct:m4", "x", "test", "y") must equal ("m4: x y")
+ mandatoryTemplate.requestBodyAndHeader("direct:m2", "x", "test", "y") must equal ("m2: x y")
+ mandatoryTemplate.requestBodyAndHeader("direct:m3", "x", "test", "y") must equal ("m3: x y")
+ mandatoryTemplate.requestBodyAndHeader("direct:m4", "x", "test", "y") must equal ("m4: x y")
}
}
"stopped" must {
@@ -94,13 +94,13 @@ class ConsumerSpec extends WordSpec with BeforeAndAfterAll with MustMatchers {
TypedActor.stop(actor)
latch.await(5000, TimeUnit.MILLISECONDS) must be (true)
intercept[CamelExecutionException] {
- template.requestBodyAndHeader("direct:m2", "x", "test", "y")
+ mandatoryTemplate.requestBodyAndHeader("direct:m2", "x", "test", "y")
}
intercept[CamelExecutionException] {
- template.requestBodyAndHeader("direct:m3", "x", "test", "y")
+ mandatoryTemplate.requestBodyAndHeader("direct:m3", "x", "test", "y")
}
intercept[CamelExecutionException] {
- template.requestBodyAndHeader("direct:m4", "x", "test", "y")
+ mandatoryTemplate.requestBodyAndHeader("direct:m4", "x", "test", "y")
}
}
}
@@ -113,8 +113,8 @@ class ConsumerSpec extends WordSpec with BeforeAndAfterAll with MustMatchers {
val latch = service.expectEndpointActivationCount(2)
actor = TypedActor.newInstance(classOf[TestTypedConsumer], classOf[TestTypedConsumerImpl])
latch.await(5000, TimeUnit.MILLISECONDS) must be (true)
- template.requestBody("direct:publish-test-3", "x") must equal ("foo: x")
- template.requestBody("direct:publish-test-4", "x") must equal ("bar: x")
+ mandatoryTemplate.requestBody("direct:publish-test-3", "x") must equal ("foo: x")
+ mandatoryTemplate.requestBody("direct:publish-test-4", "x") must equal ("bar: x")
}
}
"stopped" must {
@@ -123,10 +123,10 @@ class ConsumerSpec extends WordSpec with BeforeAndAfterAll with MustMatchers {
TypedActor.stop(actor)
latch.await(5000, TimeUnit.MILLISECONDS) must be (true)
intercept[CamelExecutionException] {
- template.requestBody("direct:publish-test-3", "x")
+ mandatoryTemplate.requestBody("direct:publish-test-3", "x")
}
intercept[CamelExecutionException] {
- template.requestBody("direct:publish-test-4", "x")
+ mandatoryTemplate.requestBody("direct:publish-test-4", "x")
}
}
}
@@ -139,7 +139,7 @@ class ConsumerSpec extends WordSpec with BeforeAndAfterAll with MustMatchers {
val latch = service.expectEndpointActivationCount(1)
consumer.start
latch.await(5000, TimeUnit.MILLISECONDS) must be (true)
- template.requestBodyAndHeader("direct:test-untyped-consumer", "x", "test", "y") must equal ("x y")
+ mandatoryTemplate.requestBodyAndHeader("direct:test-untyped-consumer", "x", "test", "y") must equal ("x y")
}
}
"stopped" must {
@@ -148,7 +148,7 @@ class ConsumerSpec extends WordSpec with BeforeAndAfterAll with MustMatchers {
consumer.stop
latch.await(5000, TimeUnit.MILLISECONDS) must be (true)
intercept[CamelExecutionException] {
- template.sendBodyAndHeader("direct:test-untyped-consumer", "blah", "test", "blub")
+ mandatoryTemplate.sendBodyAndHeader("direct:test-untyped-consumer", "blah", "test", "blub")
}
}
}
@@ -162,7 +162,7 @@ class ConsumerSpec extends WordSpec with BeforeAndAfterAll with MustMatchers {
latch.await(5000, TimeUnit.MILLISECONDS) must be (true)
try {
- template.requestBody("direct:publish-test-5", "msg3")
+ mandatoryTemplate.requestBody("direct:publish-test-5", "msg3")
fail("expected TimoutException not thrown")
} catch {
case e => {
@@ -174,7 +174,7 @@ class ConsumerSpec extends WordSpec with BeforeAndAfterAll with MustMatchers {
}
}
-object ConsumerSpec {
+object ConsumerTest {
class TestConsumer(uri: String) extends Actor with Consumer {
def endpointUri = uri
protected def receive = {
diff --git a/akka-camel/src/test/scala/ProducerFeatureTest.scala b/akka-camel/src/test/scala/ProducerFeatureTest.scala
index a27e05a54f..5f31bcbe1c 100644
--- a/akka-camel/src/test/scala/ProducerFeatureTest.scala
+++ b/akka-camel/src/test/scala/ProducerFeatureTest.scala
@@ -14,7 +14,7 @@ class ProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with Before
override protected def beforeAll = {
ActorRegistry.shutdownAll
CamelContextManager.init
- CamelContextManager.context.addRoutes(new TestRoute)
+ CamelContextManager.mandatoryContext.addRoutes(new TestRoute)
CamelContextManager.start
}
@@ -239,7 +239,7 @@ class ProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with Before
}
}
- private def mockEndpoint = CamelContextManager.context.getEndpoint("mock:mock", classOf[MockEndpoint])
+ private def mockEndpoint = CamelContextManager.mandatoryContext.getEndpoint("mock:mock", classOf[MockEndpoint])
}
object ProducerFeatureTest {
diff --git a/akka-camel/src/test/scala/RemoteConsumerTest.scala b/akka-camel/src/test/scala/RemoteConsumerTest.scala
index afba2011d5..2218aac25a 100644
--- a/akka-camel/src/test/scala/RemoteConsumerTest.scala
+++ b/akka-camel/src/test/scala/RemoteConsumerTest.scala
@@ -45,12 +45,12 @@ class RemoteConsumerTest extends FeatureSpec with BeforeAndAfterAll with GivenWh
val consumer = actorOf[RemoteConsumer].start
when("remote consumer publication is triggered")
- var latch = service.expectEndpointActivationCount(1)
+ var latch = mandatoryService.expectEndpointActivationCount(1)
consumer !! "init"
assert(latch.await(5000, TimeUnit.MILLISECONDS))
then("the published consumer is accessible via its endpoint URI")
- val response = CamelContextManager.template.requestBody("direct:remote-consumer", "test")
+ val response = CamelContextManager.mandatoryTemplate.requestBody("direct:remote-consumer", "test")
assert(response === "remote actor: test")
}
}
@@ -61,12 +61,12 @@ class RemoteConsumerTest extends FeatureSpec with BeforeAndAfterAll with GivenWh
val consumer = TypedActor.newRemoteInstance(classOf[SampleRemoteTypedConsumer], classOf[SampleRemoteTypedConsumerImpl], host, port)
when("remote typed consumer publication is triggered")
- var latch = service.expectEndpointActivationCount(1)
+ var latch = mandatoryService.expectEndpointActivationCount(1)
consumer.foo("init")
assert(latch.await(5000, TimeUnit.MILLISECONDS))
then("the published method is accessible via its endpoint URI")
- val response = CamelContextManager.template.requestBody("direct:remote-typed-consumer", "test")
+ val response = CamelContextManager.mandatoryTemplate.requestBody("direct:remote-typed-consumer", "test")
assert(response === "remote typed actor: test")
}
}
@@ -77,12 +77,12 @@ class RemoteConsumerTest extends FeatureSpec with BeforeAndAfterAll with GivenWh
val consumer = UntypedActor.actorOf(classOf[SampleRemoteUntypedConsumer]).start
when("remote untyped consumer publication is triggered")
- var latch = service.expectEndpointActivationCount(1)
+ var latch = mandatoryService.expectEndpointActivationCount(1)
consumer.sendRequestReply(Message("init", Map("test" -> "init")))
assert(latch.await(5000, TimeUnit.MILLISECONDS))
then("the published untyped consumer is accessible via its endpoint URI")
- val response = CamelContextManager.template.requestBodyAndHeader("direct:remote-untyped-consumer", "a", "test", "b")
+ val response = CamelContextManager.mandatoryTemplate.requestBodyAndHeader("direct:remote-untyped-consumer", "a", "test", "b")
assert(response === "a b")
}
}
diff --git a/akka-camel/src/test/scala/UntypedProducerFeatureTest.scala b/akka-camel/src/test/scala/UntypedProducerFeatureTest.scala
index c8a0bd8542..0d268785b6 100644
--- a/akka-camel/src/test/scala/UntypedProducerFeatureTest.scala
+++ b/akka-camel/src/test/scala/UntypedProducerFeatureTest.scala
@@ -14,7 +14,7 @@ class UntypedProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with
override protected def beforeAll = {
ActorRegistry.shutdownAll
CamelContextManager.init
- CamelContextManager.context.addRoutes(new TestRoute)
+ CamelContextManager.mandatoryContext.addRoutes(new TestRoute)
CamelContextManager.start
}
@@ -78,7 +78,7 @@ class UntypedProducerFeatureTest extends FeatureSpec with BeforeAndAfterAll with
}
- private def mockEndpoint = CamelContextManager.context.getEndpoint("mock:mock", classOf[MockEndpoint])
+ private def mockEndpoint = CamelContextManager.mandatoryContext.getEndpoint("mock:mock", classOf[MockEndpoint])
}
object UntypedProducerFeatureTest {
diff --git a/akka-camel/src/test/scala/component/ActorComponentFeatureTest.scala b/akka-camel/src/test/scala/component/ActorComponentFeatureTest.scala
index 331f2c23b6..cc9f750aae 100644
--- a/akka-camel/src/test/scala/component/ActorComponentFeatureTest.scala
+++ b/akka-camel/src/test/scala/component/ActorComponentFeatureTest.scala
@@ -18,7 +18,7 @@ class ActorComponentFeatureTest extends FeatureSpec with BeforeAndAfterAll with
override protected def beforeAll = {
ActorRegistry.shutdownAll
CamelContextManager.init
- CamelContextManager.context.addRoutes(new TestRoute)
+ CamelContextManager.mandatoryContext.addRoutes(new TestRoute)
CamelContextManager.start
}
@@ -30,12 +30,12 @@ class ActorComponentFeatureTest extends FeatureSpec with BeforeAndAfterAll with
}
feature("Communicate with an actor via an actor:uuid endpoint") {
- import CamelContextManager.template
+ import CamelContextManager.mandatoryTemplate
scenario("one-way communication") {
val actor = actorOf[Tester1].start
val latch = (actor !! SetExpectedMessageCount(1)).as[CountDownLatch].get
- template.sendBody("actor:uuid:%s" format actor.uuid, "Martin")
+ mandatoryTemplate.sendBody("actor:uuid:%s" format actor.uuid, "Martin")
assert(latch.await(5000, TimeUnit.MILLISECONDS))
val reply = (actor !! GetRetainedMessage).get.asInstanceOf[Message]
assert(reply.body === "Martin")
@@ -43,36 +43,36 @@ class ActorComponentFeatureTest extends FeatureSpec with BeforeAndAfterAll with
scenario("two-way communication") {
val actor = actorOf[Tester2].start
- assert(template.requestBody("actor:uuid:%s" format actor.uuid, "Martin") === "Hello Martin")
+ assert(mandatoryTemplate.requestBody("actor:uuid:%s" format actor.uuid, "Martin") === "Hello Martin")
}
scenario("two-way communication with timeout") {
val actor = actorOf[Tester3].start
intercept[RuntimeCamelException] {
- template.requestBody("actor:uuid:%s?blocking=true" format actor.uuid, "Martin")
+ mandatoryTemplate.requestBody("actor:uuid:%s?blocking=true" format actor.uuid, "Martin")
}
}
scenario("two-way communication via a custom route with failure response") {
mockEndpoint.expectedBodiesReceived("whatever")
- template.requestBody("direct:failure-test-1", "whatever")
+ mandatoryTemplate.requestBody("direct:failure-test-1", "whatever")
mockEndpoint.assertIsSatisfied
}
scenario("two-way communication via a custom route with exception") {
mockEndpoint.expectedBodiesReceived("whatever")
- template.requestBody("direct:failure-test-2", "whatever")
+ mandatoryTemplate.requestBody("direct:failure-test-2", "whatever")
mockEndpoint.assertIsSatisfied
}
}
feature("Communicate with an actor via an actor:id endpoint") {
- import CamelContextManager.template
+ import CamelContextManager.mandatoryTemplate
scenario("one-way communication") {
val actor = actorOf[Tester1].start
val latch = (actor !! SetExpectedMessageCount(1)).as[CountDownLatch].get
- template.sendBody("actor:%s" format actor.id, "Martin")
+ mandatoryTemplate.sendBody("actor:%s" format actor.id, "Martin")
assert(latch.await(5000, TimeUnit.MILLISECONDS))
val reply = (actor !! GetRetainedMessage).get.asInstanceOf[Message]
assert(reply.body === "Martin")
@@ -80,17 +80,17 @@ class ActorComponentFeatureTest extends FeatureSpec with BeforeAndAfterAll with
scenario("two-way communication") {
val actor = actorOf[Tester2].start
- assert(template.requestBody("actor:%s" format actor.id, "Martin") === "Hello Martin")
+ assert(mandatoryTemplate.requestBody("actor:%s" format actor.id, "Martin") === "Hello Martin")
}
scenario("two-way communication via a custom route") {
val actor = actorOf[CustomIdActor].start
- assert(template.requestBody("direct:custom-id-test-1", "Martin") === "Received Martin")
- assert(template.requestBody("direct:custom-id-test-2", "Martin") === "Received Martin")
+ assert(mandatoryTemplate.requestBody("direct:custom-id-test-1", "Martin") === "Received Martin")
+ assert(mandatoryTemplate.requestBody("direct:custom-id-test-2", "Martin") === "Received Martin")
}
}
- private def mockEndpoint = CamelContextManager.context.getEndpoint("mock:mock", classOf[MockEndpoint])
+ private def mockEndpoint = CamelContextManager.mandatoryContext.getEndpoint("mock:mock", classOf[MockEndpoint])
}
object ActorComponentFeatureTest {
diff --git a/akka-camel/src/test/scala/component/ActorComponentTest.scala b/akka-camel/src/test/scala/component/ActorComponentTest.scala
index f35e8b3885..50c6e664e7 100644
--- a/akka-camel/src/test/scala/component/ActorComponentTest.scala
+++ b/akka-camel/src/test/scala/component/ActorComponentTest.scala
@@ -4,6 +4,7 @@ import org.apache.camel.{Endpoint, AsyncProcessor}
import org.apache.camel.impl.DefaultCamelContext
import org.junit._
import org.scalatest.junit.JUnitSuite
+
import se.scalablesolutions.akka.actor.uuidFrom
class ActorComponentTest extends JUnitSuite {
diff --git a/akka-camel/src/test/scala/component/TypedActorComponentFeatureTest.scala b/akka-camel/src/test/scala/component/TypedActorComponentFeatureTest.scala
index 06f7e29173..e1f169187a 100644
--- a/akka-camel/src/test/scala/component/TypedActorComponentFeatureTest.scala
+++ b/akka-camel/src/test/scala/component/TypedActorComponentFeatureTest.scala
@@ -1,20 +1,19 @@
package se.scalablesolutions.akka.camel.component
+import org.apache.camel._
+import org.apache.camel.builder.RouteBuilder
+import org.apache.camel.impl.{DefaultCamelContext, SimpleRegistry}
import org.scalatest.{BeforeAndAfterEach, BeforeAndAfterAll, FeatureSpec}
-import org.apache.camel.builder.RouteBuilder
-import se.scalablesolutions.akka.actor.Actor._
import se.scalablesolutions.akka.actor.{ActorRegistry, TypedActor}
import se.scalablesolutions.akka.camel._
-import org.apache.camel.impl.{DefaultCamelContext, SimpleRegistry}
-import org.apache.camel.{ResolveEndpointFailedException, ExchangePattern, Exchange, Processor}
/**
* @author Martin Krasser
*/
class TypedActorComponentFeatureTest extends FeatureSpec with BeforeAndAfterAll with BeforeAndAfterEach {
import TypedActorComponentFeatureTest._
- import CamelContextManager.template
+ import CamelContextManager.mandatoryTemplate
override protected def beforeAll = {
val typedActor = TypedActor.newInstance(classOf[SampleTypedActor], classOf[SampleTypedActorImpl]) // not a consumer
@@ -25,7 +24,7 @@ class TypedActorComponentFeatureTest extends FeatureSpec with BeforeAndAfterAll
registry.put("ta", typedActor)
CamelContextManager.init(new DefaultCamelContext(registry))
- CamelContextManager.context.addRoutes(new CustomRouteBuilder)
+ CamelContextManager.mandatoryContext.addRoutes(new CustomRouteBuilder)
CamelContextManager.start
// Internal registration
@@ -42,19 +41,19 @@ class TypedActorComponentFeatureTest extends FeatureSpec with BeforeAndAfterAll
import ExchangePattern._
scenario("two-way communication with method returning String") {
- val result1 = template.requestBodyAndHeader("%s:tc?method=m2" format InternalSchema, "x", "test", "y")
- val result2 = template.requestBodyAndHeader("%s:tc?method=m4" format InternalSchema, "x", "test", "y")
+ val result1 = mandatoryTemplate.requestBodyAndHeader("%s:tc?method=m2" format InternalSchema, "x", "test", "y")
+ val result2 = mandatoryTemplate.requestBodyAndHeader("%s:tc?method=m4" format InternalSchema, "x", "test", "y")
assert(result1 === "m2: x y")
assert(result2 === "m4: x y")
}
scenario("two-way communication with method returning void") {
- val result = template.requestBodyAndHeader("%s:tc?method=m5" format InternalSchema, "x", "test", "y")
+ val result = mandatoryTemplate.requestBodyAndHeader("%s:tc?method=m5" format InternalSchema, "x", "test", "y")
assert(result === "x") // returns initial body
}
scenario("one-way communication with method returning String") {
- val result = template.send("%s:tc?method=m2" format InternalSchema, InOnly, new Processor {
+ val result = mandatoryTemplate.send("%s:tc?method=m2" format InternalSchema, InOnly, new Processor {
def process(exchange: Exchange) = {
exchange.getIn.setBody("x")
exchange.getIn.setHeader("test", "y")
@@ -66,7 +65,7 @@ class TypedActorComponentFeatureTest extends FeatureSpec with BeforeAndAfterAll
}
scenario("one-way communication with method returning void") {
- val result = template.send("%s:tc?method=m5" format InternalSchema, InOnly, new Processor {
+ val result = mandatoryTemplate.send("%s:tc?method=m5" format InternalSchema, InOnly, new Processor {
def process(exchange: Exchange) = {
exchange.getIn.setBody("x")
exchange.getIn.setHeader("test", "y")
@@ -82,19 +81,19 @@ class TypedActorComponentFeatureTest extends FeatureSpec with BeforeAndAfterAll
feature("Communicate with an internally-registered typed actor using typed-actor endpoint URIs") {
scenario("communication not possible") {
intercept[ResolveEndpointFailedException] {
- template.requestBodyAndHeader("typed-actor:tc?method=m2", "x", "test", "y")
+ mandatoryTemplate.requestBodyAndHeader("typed-actor:tc?method=m2", "x", "test", "y")
}
}
}
feature("Communicate with an externally-registered typed actor using typed-actor endpoint URIs") {
scenario("two-way communication with method returning String") {
- val result = template.requestBody("typed-actor:ta?method=foo", "test")
+ val result = mandatoryTemplate.requestBody("typed-actor:ta?method=foo", "test")
assert(result === "foo: test")
}
scenario("two-way communication with method returning String via custom route") {
- val result = template.requestBody("direct:test", "test")
+ val result = mandatoryTemplate.requestBody("direct:test", "test")
assert(result === "foo: test")
}
}
diff --git a/akka-http/src/main/scala/AkkaBroadcaster.scala b/akka-http/src/main/scala/AkkaBroadcaster.scala
index ca5abc6f1d..8aae04bc86 100644
--- a/akka-http/src/main/scala/AkkaBroadcaster.scala
+++ b/akka-http/src/main/scala/AkkaBroadcaster.scala
@@ -5,23 +5,27 @@
package se.scalablesolutions.akka.comet
import org.atmosphere.cpr.{AtmosphereResourceEvent, AtmosphereResource}
+
import se.scalablesolutions.akka.actor.Actor._
import se.scalablesolutions.akka.actor.Actor
import se.scalablesolutions.akka.dispatch.Dispatchers
+import org.atmosphere.jersey.util.JerseyBroadcasterUtil
object AkkaBroadcaster {
val broadcasterDispatcher = Dispatchers.fromConfig("akka.rest.comet-dispatcher")
+
+ type Event = AtmosphereResourceEvent[_,_]
+ type Resource = AtmosphereResource[_,_]
}
-class AkkaBroadcaster extends org.atmosphere.jersey.JerseyBroadcaster {
+class AkkaBroadcaster extends org.atmosphere.jersey.util.JerseySimpleBroadcaster {
import AkkaBroadcaster._
- name = classOf[AkkaBroadcaster].getName
//FIXME should be supervised
- val caster = actorOf(new Actor {
+ lazy val caster = actorOf(new Actor {
self.dispatcher = broadcasterDispatcher
def receive = {
- case f : Function0[_] => f()
+ case (r: Resource,e: Event) => JerseyBroadcasterUtil.broadcast(r,e)
}
}).start
@@ -30,7 +34,7 @@ class AkkaBroadcaster extends org.atmosphere.jersey.JerseyBroadcaster {
caster.stop
}
- protected override def broadcast(r : AtmosphereResource[_,_], e : AtmosphereResourceEvent[_,_]) = {
- caster ! (() => super.broadcast(r,e))
+ protected override def broadcast(r: Resource, e : Event) {
+ caster ! ((r,e))
}
-}
+}
\ No newline at end of file
diff --git a/akka-http/src/main/scala/AkkaCometServlet.scala b/akka-http/src/main/scala/AkkaCometServlet.scala
index 4a3d61cc10..6afb216c9b 100644
--- a/akka-http/src/main/scala/AkkaCometServlet.scala
+++ b/akka-http/src/main/scala/AkkaCometServlet.scala
@@ -42,32 +42,30 @@ class AtmosphereRestServlet extends ServletContainer with AtmosphereServletProce
*
- * trait ZScorable {
+ * trait ZScorable {
* def toZScore: Float
* }
*
- * class Foo extends ZScorable {
+ * class Foo extends ZScorable {
* //.. implemnetation
* }
*
* Or we can also use views:
*
- * class Foo {
+ * class Foo {
* //..
* }
*
- * implicit def Foo2Scorable(foo: Foo): ZScorable = new ZScorable {
- * def toZScore = {
+ * implicit def Foo2Scorable(foo: Foo): ZScorable = new ZScorable {
+ * def toZScore = {
* //..
- * }
+ * }
* }
*
*
@@ -682,7 +730,6 @@ trait PersistentQueue[A] extends scala.collection.mutable.Queue[A]
* @author
*/
trait PersistentSortedSet[A] extends Transactional with Committable with Abortable {
-
protected val newElems = TransactionalMap[A, Float]()
protected val removedElems = TransactionalVector[A]()
@@ -715,8 +762,8 @@ trait PersistentSortedSet[A] extends Transactional with Committable with Abortab
}
private def inStorage(elem: A): Option[Float] = storage.zscore(uuid, elem) match {
- case Some(s) => Some(s.toFloat)
- case None => None
+ case Some(s) => Some(s.toFloat)
+ case None => None
}
def contains(elem: A): Boolean = {
@@ -744,11 +791,10 @@ trait PersistentSortedSet[A] extends Transactional with Committable with Abortab
def compare(that: (A, Float)) = x._2 compare that._2
}
- implicit def ordering = new scala.math.Ordering[(A,Float)] {
- def compare(x: (A, Float),y : (A,Float)) = x._2 compare y._2
+ implicit def ordering = new scala.math.Ordering[(A, Float)] {
+ def compare(x: (A, Float), y: (A, Float)) = x._2 compare y._2
}
-
def zrange(start: Int, end: Int): List[(A, Float)] = {
// need to operate on the whole range
// get all from the underlying storage
@@ -759,14 +805,14 @@ trait PersistentSortedSet[A] extends Transactional with Committable with Abortab
// -1 means the last element, -2 means the second last
val s = if (start < 0) start + l else start
val e =
- if (end < 0) end + l
- else if (end >= l) (l - 1)
- else end
+ if (end < 0) end + l
+ else if (end >= l) (l - 1)
+ else end
// slice is open at the end, we need a closed end range
ts.iterator.slice(s, e + 1).toList
}
- private def register = {
+ protected def register = {
if (transaction.get.isEmpty) throw new NoTransactionInScopeException
transaction.get.get.register(uuid, this)
}
diff --git a/akka-persistence/akka-persistence-common/src/test/scala/MapStorageBackendTest.scala b/akka-persistence/akka-persistence-common/src/test/scala/MapStorageBackendTest.scala
new file mode 100644
index 0000000000..395d0ef269
--- /dev/null
+++ b/akka-persistence/akka-persistence-common/src/test/scala/MapStorageBackendTest.scala
@@ -0,0 +1,161 @@
+/**
+ * Copyright (C) 2009-2010 Scalable Solutions AB
+ * MyPojo pojo = TypedActor.newInstance(MyPojo.class, new TypedActorFactory() {
+ * public TypedActor create() {
+ * return new MyTypedActor("service:name", 5);
+ * }
+ * });
+ *
+ */
+ def newInstance[T](intfClass: Class[T], factory: TypedActorFactory) : T =
+ newInstance(intfClass, factory.create)
+
+ /**
+ * Java API.
+ */
+ def newRemoteInstance[T](intfClass: Class[T], factory: TypedActorFactory, hostname: String, port: Int) : T =
+ newRemoteInstance(intfClass, factory.create, hostname, port)
+
+ /**
+ * Java API.
+ */
+ def newRemoteInstance[T](intfClass: Class[T], factory: TypedActorFactory, timeout: Long, hostname: String, port: Int) : T =
+ newRemoteInstance(intfClass, factory.create, timeout, hostname, port)
+
+ /**
+ * Java API.
+ */
+ def newInstance[T](intfClass: Class[T], factory: TypedActorFactory, timeout: Long) : T =
+ newInstance(intfClass, factory.create, timeout)
+
+ /**
+ * Java API.
+ */
+ def newInstance[T](intfClass: Class[T], factory: TypedActorFactory, config: TypedActorConfiguration): T =
+ newInstance(intfClass, factory.create, config)
/**
* Create a proxy for a RemoteActorRef representing a server managed remote typed actor.
@@ -467,13 +626,24 @@ object TypedActor extends Logging {
def stop(proxy: AnyRef): Unit = AspectInitRegistry.unregister(proxy)
/**
- * Get the underlying dispatcher actor for the given Typed Actor.
+ * Get the underlying typed actor for the given Typed Actor.
*/
def actorFor(proxy: AnyRef): Option[ActorRef] =
ActorRegistry
.actorsFor(classOf[TypedActor])
.find(a => a.actor.asInstanceOf[TypedActor].proxy == proxy)
+ /**
+ * Get the typed actor proxy for the given Typed Actor.
+ */
+ def proxyFor(actorRef: ActorRef): Option[AnyRef] = {
+ if (actorRef.actor.isInstanceOf[TypedActor]) {
+ Some(actorRef.actor.asInstanceOf[TypedActor].proxy)
+ } else {
+ None
+ }
+ }
+
/**
* Links an other Typed Actor to this Typed Actor.
* @param supervisor the supervisor Typed Actor
@@ -495,13 +665,12 @@ object TypedActor extends Logging {
* @param trapExceptions array of exceptions that should be handled by the supervisor
*/
def link(supervisor: AnyRef, supervised: AnyRef,
- handler: FaultHandlingStrategy, trapExceptions: Array[Class[_ <: Throwable]]) = {
+ handler: FaultHandlingStrategy) = {
val supervisorActor = actorFor(supervisor).getOrElse(
throw new IllegalActorStateException("Can't link when the supervisor is not an Typed Actor"))
val supervisedActor = actorFor(supervised).getOrElse(
throw new IllegalActorStateException("Can't link when the supervised is not an Typed Actor"))
- supervisorActor.trapExit = trapExceptions.toList
- supervisorActor.faultHandler = Some(handler)
+ supervisorActor.faultHandler = handler
supervisorActor.link(supervisedActor)
}
@@ -518,18 +687,6 @@ object TypedActor extends Logging {
supervisorActor.unlink(supervisedActor)
}
- /**
- * Sets the trap exit for the given supervisor Typed Actor.
- * @param supervisor the supervisor Typed Actor
- * @param trapExceptions array of exceptions that should be handled by the supervisor
- */
- def trapExit(supervisor: AnyRef, trapExceptions: Array[Class[_ <: Throwable]]) = {
- val supervisorActor = actorFor(supervisor).getOrElse(
- throw new IllegalActorStateException("Can't set trap exceptions when the supervisor is not an Typed Actor"))
- supervisorActor.trapExit = trapExceptions.toList
- this
- }
-
/**
* Sets the fault handling strategy for the given supervisor Typed Actor.
* @param supervisor the supervisor Typed Actor
@@ -538,12 +695,12 @@ object TypedActor extends Logging {
def faultHandler(supervisor: AnyRef, handler: FaultHandlingStrategy) = {
val supervisorActor = actorFor(supervisor).getOrElse(
throw new IllegalActorStateException("Can't set fault handler when the supervisor is not an Typed Actor"))
- supervisorActor.faultHandler = Some(handler)
+ supervisorActor.faultHandler = handler
this
}
def isTransactional(clazz: Class[_]): Boolean = {
- if (clazz == null) false
+ if (clazz eq null) false
else if (clazz.isAssignableFrom(classOf[TypedTransactor])) true
else isTransactional(clazz.getSuperclass)
}
@@ -557,6 +714,15 @@ object TypedActor extends Logging {
typedActor
}
+ private[akka] def newTypedActor(factory: => AnyRef): TypedActor = {
+ val instance = factory
+ val typedActor =
+ if (instance.isInstanceOf[TypedActor]) instance.asInstanceOf[TypedActor]
+ else throw new IllegalArgumentException("Actor [" + instance.getClass.getName + "] is not a sub class of 'TypedActor'")
+ typedActor.preStart
+ typedActor
+ }
+
private[akka] def isOneWay(joinPoint: JoinPoint): Boolean =
isOneWay(joinPoint.getRtti.asInstanceOf[MethodRtti])
diff --git a/akka-typed-actor/src/test/scala/actor/typed-actor/RestartNestedTransactionalTypedActorSpec.scala b/akka-typed-actor/src/test/scala/actor/typed-actor/RestartNestedTransactionalTypedActorSpec.scala
index 1769a5c47b..ea5db11531 100644
--- a/akka-typed-actor/src/test/scala/actor/typed-actor/RestartNestedTransactionalTypedActorSpec.scala
+++ b/akka-typed-actor/src/test/scala/actor/typed-actor/RestartNestedTransactionalTypedActorSpec.scala
@@ -33,13 +33,13 @@ class RestartNestedTransactionalTypedActorSpec extends
new RestartStrategy(new AllForOne, 3, 5000, List(classOf[Exception]).toArray),
List(
new Component(classOf[TransactionalTypedActor],
- new LifeCycle(new Permanent),
+ new Permanent,
10000),
new Component(classOf[NestedTransactionalTypedActor],
- new LifeCycle(new Permanent),
+ new Permanent,
10000),
new Component(classOf[TypedActorFailer],
- new LifeCycle(new Permanent),
+ new Permanent,
10000)
).toArray).supervise
*/
diff --git a/akka-typed-actor/src/test/scala/actor/typed-actor/RestartTransactionalTypedActorSpec.scala b/akka-typed-actor/src/test/scala/actor/typed-actor/RestartTransactionalTypedActorSpec.scala
index 56b1e6ec5b..8f80fbcd1b 100644
--- a/akka-typed-actor/src/test/scala/actor/typed-actor/RestartTransactionalTypedActorSpec.scala
+++ b/akka-typed-actor/src/test/scala/actor/typed-actor/RestartTransactionalTypedActorSpec.scala
@@ -33,11 +33,11 @@ class RestartTransactionalTypedActorSpec extends
List(
new Component(
classOf[TransactionalTypedActor],
- new LifeCycle(new Temporary),
+ new Temporary,
10000),
new Component(
classOf[TypedActorFailer],
- new LifeCycle(new Temporary),
+ new Temporary,
10000)
).toArray).supervise
}
diff --git a/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorGuiceConfiguratorSpec.scala b/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorGuiceConfiguratorSpec.scala
index d076ec52cf..814cd299d9 100644
--- a/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorGuiceConfiguratorSpec.scala
+++ b/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorGuiceConfiguratorSpec.scala
@@ -41,13 +41,13 @@ class TypedActorGuiceConfiguratorSpec extends
new Component(
classOf[Foo],
classOf[FooImpl],
- new LifeCycle(new Permanent),
+ new Permanent,
1000,
dispatcher),
new Component(
classOf[Bar],
classOf[BarImpl],
- new LifeCycle(new Permanent),
+ new Permanent,
1000,
dispatcher)
).toArray).inject.supervise
diff --git a/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorLifecycleSpec.scala b/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorLifecycleSpec.scala
index 052f4cc7de..f2903adf03 100644
--- a/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorLifecycleSpec.scala
+++ b/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorLifecycleSpec.scala
@@ -22,8 +22,8 @@ class TypedActorLifecycleSpec extends Spec with ShouldMatchers with BeforeAndAft
override protected def beforeAll() = {
val strategy = new RestartStrategy(new AllForOne(), 3, 1000, Array(classOf[Exception]))
- val comp3 = new Component(classOf[SamplePojo], classOf[SamplePojoImpl], new LifeCycle(new Permanent()), 1000)
- val comp4 = new Component(classOf[SamplePojo], classOf[SamplePojoImpl], new LifeCycle(new Temporary()), 1000)
+ val comp3 = new Component(classOf[SamplePojo], classOf[SamplePojoImpl], new Permanent(), 1000)
+ val comp4 = new Component(classOf[SamplePojo], classOf[SamplePojoImpl], new Temporary(), 1000)
conf1 = new TypedActorConfigurator().configure(strategy, Array(comp3)).supervise
conf2 = new TypedActorConfigurator().configure(strategy, Array(comp4)).supervise
}
@@ -87,7 +87,7 @@ class TypedActorLifecycleSpec extends Spec with ShouldMatchers with BeforeAndAft
SamplePojoImpl.reset
val pojo = TypedActor.newInstance(classOf[SimpleJavaPojo], classOf[SimpleJavaPojoImpl])
val supervisor = TypedActor.newInstance(classOf[SimpleJavaPojo], classOf[SimpleJavaPojoImpl])
- link(supervisor, pojo, OneForOneStrategy(3, 2000), Array(classOf[Throwable]))
+ link(supervisor, pojo, OneForOneStrategy(Array(classOf[Throwable]), 3, 2000))
pojo.throwException
Thread.sleep(500)
SimpleJavaPojoImpl._pre should be(true)
diff --git a/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorSpec.scala b/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorSpec.scala
index 7de0a8f5df..13c8c8e1fa 100644
--- a/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorSpec.scala
+++ b/akka-typed-actor/src/test/scala/actor/typed-actor/TypedActorSpec.scala
@@ -7,25 +7,164 @@ package se.scalablesolutions.akka.actor
import org.scalatest.Spec
import org.scalatest.Assertions
import org.scalatest.matchers.ShouldMatchers
-import org.scalatest.BeforeAndAfterAll
+import org.scalatest.BeforeAndAfterEach
import org.scalatest.junit.JUnitRunner
import org.junit.runner.RunWith
-import se.scalablesolutions.akka.dispatch.DefaultCompletableFuture;
+import se.scalablesolutions.akka.dispatch.DefaultCompletableFuture
+import TypedActorSpec._
+
+
+object TypedActorSpec {
+ trait MyTypedActor {
+ def sendOneWay(msg: String) : Unit
+ def sendRequestReply(msg: String) : String
+ }
+
+ class MyTypedActorImpl extends TypedActor with MyTypedActor {
+ self.id = "my-custom-id"
+ def sendOneWay(msg: String) {
+ println("got " + msg )
+ }
+ def sendRequestReply(msg: String) : String = {
+ "got " + msg
+ }
+ }
+
+ class MyTypedActorWithConstructorArgsImpl(aString: String, aLong: Long) extends TypedActor with MyTypedActor {
+ self.id = "my-custom-id"
+ def sendOneWay(msg: String) {
+ println("got " + msg + " " + aString + " " + aLong)
+ }
+
+ def sendRequestReply(msg: String) : String = {
+ msg + " " + aString + " " + aLong
+ }
+ }
+
+ class MyActor extends Actor {
+ self.id = "my-custom-id"
+ def receive = {
+ case msg: String => println("got " + msg)
+ }
+ }
+
+}
+
@RunWith(classOf[JUnitRunner])
class TypedActorSpec extends
Spec with
ShouldMatchers with
- BeforeAndAfterAll {
+ BeforeAndAfterEach {
+
+ var simplePojo: SimpleJavaPojo = null
+ var pojo: MyTypedActor = null;
+
+ override def beforeEach() {
+ simplePojo = TypedActor.newInstance(classOf[SimpleJavaPojo], classOf[SimpleJavaPojoImpl])
+ pojo = TypedActor.newInstance(classOf[MyTypedActor], classOf[MyTypedActorImpl])
+ }
+
+ override def afterEach() {
+ ActorRegistry.shutdownAll
+ }
describe("TypedActor") {
+
it("should resolve Future return from method defined to return a Future") {
- val pojo = TypedActor.newInstance(classOf[SimpleJavaPojo], classOf[SimpleJavaPojoImpl])
- val future = pojo.square(10)
+ val future = simplePojo.square(10)
future.await
future.result.isDefined should equal (true)
future.result.get should equal (100)
}
+
+ it("should accept constructor arguments") {
+ val pojo1 = TypedActor.newInstance(classOf[MyTypedActor], new MyTypedActorWithConstructorArgsImpl("test", 1L))
+ assert(pojo1.sendRequestReply("hello") === "hello test 1")
+
+ val pojo2 = TypedActor.newInstance(classOf[MyTypedActor], new MyTypedActorWithConstructorArgsImpl("test2", 2L), new TypedActorConfiguration())
+ assert(pojo2.sendRequestReply("hello") === "hello test2 2")
+
+ val pojo3 = TypedActor.newInstance(classOf[MyTypedActor], new MyTypedActorWithConstructorArgsImpl("test3", 3L), 5000L)
+ assert(pojo3.sendRequestReply("hello") === "hello test3 3")
+ }
+ }
+
+ describe("TypedActor object") {
+ it("should support finding the underlying actor for a given proxy and the proxy for a given actor") {
+ val typedActorRef = TypedActor.actorFor(simplePojo).get
+ val typedActor = typedActorRef.actor.asInstanceOf[TypedActor]
+ assert(typedActor.proxy === simplePojo)
+ assert(TypedActor.proxyFor(typedActorRef).get === simplePojo)
+ }
+ }
+
+ describe("ActorRegistry") {
+ it("should support finding a typed actor by uuid ") {
+ val typedActorRef = TypedActor.actorFor(simplePojo).get
+ val uuid = typedActorRef.uuid
+ assert(ActorRegistry.typedActorFor(newUuid()) === None)
+ assert(ActorRegistry.typedActorFor(uuid).isDefined)
+ assert(ActorRegistry.typedActorFor(uuid).get === simplePojo)
+ }
+
+ it("should support finding typed actors by id ") {
+ val typedActors = ActorRegistry.typedActorsFor("my-custom-id")
+ assert(typedActors.length === 1)
+ assert(typedActors.contains(pojo))
+
+ // creating untyped actor with same custom id
+ val actorRef = Actor.actorOf[MyActor].start
+ val typedActors2 = ActorRegistry.typedActorsFor("my-custom-id")
+ assert(typedActors2.length === 1)
+ assert(typedActors2.contains(pojo))
+ actorRef.stop
+ }
+
+ it("should support to filter typed actors") {
+ val actors = ActorRegistry.filterTypedActors(ta => ta.isInstanceOf[MyTypedActor])
+ assert(actors.length === 1)
+ assert(actors.contains(pojo))
+ }
+
+ it("should support to find typed actors by class") {
+ val actors = ActorRegistry.typedActorsFor(classOf[MyTypedActorImpl])
+ assert(actors.length === 1)
+ assert(actors.contains(pojo))
+ assert(ActorRegistry.typedActorsFor(classOf[MyActor]).isEmpty)
+ }
+
+ it("should support to get all typed actors") {
+ val actors = ActorRegistry.typedActors
+ assert(actors.length === 2)
+ assert(actors.contains(pojo))
+ assert(actors.contains(simplePojo))
+ }
+
+ it("should support to find typed actors by manifest") {
+ val actors = ActorRegistry.typedActorsFor[MyTypedActorImpl]
+ assert(actors.length === 1)
+ assert(actors.contains(pojo))
+ assert(ActorRegistry.typedActorsFor[MyActor].isEmpty)
+ }
+
+ it("should support foreach for typed actors") {
+ val actorRef = Actor.actorOf[MyActor].start
+ assert(ActorRegistry.actors.size === 3)
+ assert(ActorRegistry.typedActors.size === 2)
+ ActorRegistry.foreachTypedActor(TypedActor.stop(_))
+ assert(ActorRegistry.actors.size === 1)
+ assert(ActorRegistry.typedActors.size === 0)
+ }
+
+ it("should shutdown all typed and untyped actors") {
+ val actorRef = Actor.actorOf[MyActor].start
+ assert(ActorRegistry.actors.size === 3)
+ assert(ActorRegistry.typedActors.size === 2)
+ ActorRegistry.shutdownAll()
+ assert(ActorRegistry.actors.size === 0)
+ assert(ActorRegistry.typedActors.size === 0)
+ }
}
}
diff --git a/config/akka-reference.conf b/config/akka-reference.conf
index eec56c7f06..b2202fb669 100644
--- a/config/akka-reference.conf
+++ b/config/akka-reference.conf
@@ -25,7 +25,7 @@ akka {
# - TypedActor: methods with non-void return type
serialize-messages = off # Does a deep clone of (non-primitive) messages to ensure immutability
throughput = 5 # Default throughput for all ExecutorBasedEventDrivenDispatcher, set to 1 for complete fairness
- throughput-deadline-ms = -1 # Default throughput deadline for all ExecutorBasedEventDrivenDispatcher, set to 0 or negative for no deadline
+ throughput-deadline-time = -1 # Default throughput deadline for all ExecutorBasedEventDrivenDispatcher, set to 0 or negative for no deadline
default-dispatcher {
type = "GlobalExecutorBasedEventDriven" # Must be one of the following, all "Global*" are non-configurable
@@ -38,14 +38,14 @@ akka {
# - GlobalExecutorBasedEventDriven
# - GlobalReactorBasedSingleThreadEventDriven
# - GlobalReactorBasedThreadPoolEventDriven
- keep-alive-ms = 60000 # Keep alive time for threads
+ keep-alive-time = 60 # Keep alive time for threads
core-pool-size-factor = 1.0 # No of core threads ... ceil(available processors * factor)
max-pool-size-factor = 4.0 # Max no of threads ... ceil(available processors * factor)
executor-bounds = -1 # Makes the Executor bounded, -1 is unbounded
allow-core-timeout = on # Allow core threads to time out
rejection-policy = "caller-runs" # abort, caller-runs, discard-oldest, discard
throughput = 5 # Throughput for ExecutorBasedEventDrivenDispatcher, set to 1 for complete fairness
- throughput-deadline-ms = -1 # Throughput deadline for ExecutorBasedEventDrivenDispatcher, set to 0 or negative for no deadline
+ throughput-deadline-time = -1 # Throughput deadline for ExecutorBasedEventDrivenDispatcher, set to 0 or negative for no deadline
aggregate = off # Aggregate on/off for HawtDispatchers
mailbox-capacity = -1 # If negative (or zero) then an unbounded mailbox is used (default)
# If positive then a bounded mailbox is used and the capacity is set using the property
@@ -54,7 +54,8 @@ akka {
#
# The following are only used for ExecutorBasedEventDriven
# and only if mailbox-capacity > 0
- mailbox-push-timeout-ms = 10000 # Specifies the timeout (in milliseconds) to add a new message to a mailbox that is full
+ mailbox-push-timeout-time = 10 # Specifies the timeout to add a new message to a mailbox that is full - negative number means infinite timeout
+ # (in unit defined by the time-unit property)
}
}
@@ -166,21 +167,24 @@ akka {
}
hbase {
- zookeeper-quorum = "localhost"
+ zookeeper-quorum = "localhost" # A comma separated list of hostnames or IPs of the zookeeper quorum instances
}
voldemort {
store {
- refs = "Refs" # Voldemort Store Used to Persist Refs. Use string serializer for keys, identity serializer for values
- map-keys = "MapKeys" # Voldemort Store Used to Persist Map Keys. Use string serializer for keys, identity serializer for values
- map-values = "MapValues" # Voldemort Store Used to Persist Map Values. Use identity serializer for keys, identity serializer for values
- vector-sizes = "VectorSizes" # Voldemort Store Used to Persist Vector Sizes. Use string serializer for keys, identity serializer for values
- vector-values = "VectorValues" # Voldemort Store Used to Persist Vector Values. Use identity serializer for keys, identity serializer for values
+ ref = "Refs" # Voldemort Store Used to Persist Refs. Use string serializer for keys, identity serializer for values
+ maps = "Maps" # Voldemort Store Used to Persist Map Keys. Use identity serializer for keys, identity serializer for values
+ vector = "Vectors" # Voldemort Store Used to Persist Vector Sizes. Use identity serializer for keys, identity serializer for values
+ queue = "Queues" # Voldemort Store Used to Persist Vector Values. Use identity serializer for keys, identity serializer for values
}
- client { # The KeyValue pairs under client are converted to java Properties and used to construct the ClientConfig
+ client { # The KeyValue pairs under client are converted to java Properties and used to construct the Voldemort ClientConfig
bootstrap_urls = "tcp://localhost:6666" # All Valid Voldemort Client properties are valid here, in string form
}
}
}
+
+ camel {
+ service = on
+ }
}
diff --git a/embedded-repo/com/redis/redisclient/2.8.0-2.0.1/redisclient-2.8.0-2.0.1.jar b/embedded-repo/com/redis/redisclient/2.8.0-2.0.1/redisclient-2.8.0-2.0.1.jar
new file mode 100644
index 0000000000..7709ef140b
Binary files /dev/null and b/embedded-repo/com/redis/redisclient/2.8.0-2.0.1/redisclient-2.8.0-2.0.1.jar differ
diff --git a/embedded-repo/com/redis/redisclient/2.8.0-2.0.1/redisclient-2.8.0-2.0.1.pom b/embedded-repo/com/redis/redisclient/2.8.0-2.0.1/redisclient-2.8.0-2.0.1.pom
new file mode 100644
index 0000000000..4010889e31
--- /dev/null
+++ b/embedded-repo/com/redis/redisclient/2.8.0-2.0.1/redisclient-2.8.0-2.0.1.pom
@@ -0,0 +1,8 @@
+
+